pazpar2  1.14.1
http_command.c
Go to the documentation of this file.
1 /* This file is part of Pazpar2.
2  Copyright (C) Index Data
3 
4 Pazpar2 is free software; you can redistribute it and/or modify it under
5 the terms of the GNU General Public License as published by the Free
6 Software Foundation; either version 2, or (at your option) any later
7 version.
8 
9 Pazpar2 is distributed in the hope that it will be useful, but WITHOUT ANY
10 WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 for more details.
13 
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 
18 */
19 
20 #if HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23 #include <stdio.h>
24 #include <sys/types.h>
25 #if HAVE_UNISTD_H
26 #include <unistd.h>
27 #endif
28 #include <stdlib.h>
29 #include <string.h>
30 #if HAVE_SYS_TIME_H
31 #include <sys/time.h>
32 #endif
33 #include <yaz/snprintf.h>
34 #include <yaz/yaz-util.h>
35 #include <yaz/malloc_info.h>
36 
37 #include "ppmutex.h"
38 #include "eventl.h"
39 #include "parameters.h"
40 #include "session.h"
41 #include "http.h"
42 #include "settings.h"
43 #include "client.h"
44 
45 // Update this when the protocol changes
46 #define PAZPAR2_PROTOCOL_VERSION "1"
47 
48 #define HTTP_COMMAND_RESPONSE_PREFIX "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
49 
50 struct http_session {
51  IOCHAN timeout_iochan; // NOTE: This is NOT associated with a socket
52  struct session *psession;
53  unsigned int session_id;
54  int timestamp;
57  NMEM nmem;
59  struct http_session *next;
60 };
61 
62 struct http_sessions {
64  YAZ_MUTEX mutex;
65  int log_level;
66 };
67 
68 static YAZ_MUTEX g_http_session_mutex = 0;
69 static int g_http_sessions = 0;
70 
71 static void show_records_ready(void *data);
72 
73 int get_version(struct http_request *rq) {
74  const char *version = http_argbyname(rq, "version");
75  int version_no = 0;
76  if (version && strcmp(version, "")) {
77  version_no = atoi(version);
78  }
79  return version_no;
80 }
81 
82 
83 int http_session_use(int delta)
84 {
85  int sessions;
87  yaz_mutex_create(&g_http_session_mutex);
88  yaz_mutex_enter(g_http_session_mutex);
89  g_http_sessions += delta;
90  sessions = g_http_sessions;
91  yaz_mutex_leave(g_http_session_mutex);
92  yaz_log(YLOG_DEBUG, "%s http_sessions=%d", delta == 0 ? "" :
93  (delta > 0 ? "INC" : "DEC"), sessions);
94  return sessions;
95 
96 }
97 
99 {
100  http_sessions_t hs = xmalloc(sizeof(*hs));
101  hs->session_list = 0;
102  hs->mutex = 0;
103  pazpar2_mutex_create(&hs->mutex, "http_sessions");
104  hs->log_level = yaz_log_module_level("http");
105  return hs;
106 }
107 
109 {
110  if (hs)
111  {
112  struct http_session *s = hs->session_list;
113  while (s)
114  {
115  struct http_session *s_next = s->next;
118  nmem_destroy(s->nmem);
119  s = s_next;
120  }
121  yaz_mutex_destroy(&hs->mutex);
122  xfree(hs);
123  }
124 }
125 
126 void http_session_destroy(struct http_session *s);
127 
128 static void session_timeout(IOCHAN i, int event)
129 {
130  struct http_session *s = iochan_getdata(i);
132 }
133 
136  unsigned int sesid)
137 {
138  NMEM nmem = nmem_create();
139  struct http_session *r = nmem_malloc(nmem, sizeof(*r));
140  char tmp_str[50];
141 
142  sprintf(tmp_str, "session#%u", sesid);
143  r->psession = session_create(nmem, service, sesid);
144  r->session_id = sesid;
145  r->timestamp = 0;
146  r->nmem = nmem;
147  r->destroy_counter = r->activity_counter = 0;
149 
150  yaz_mutex_enter(http_sessions->mutex);
153  yaz_mutex_leave(http_sessions->mutex);
154 
156  "http_session_timeout");
158 
160  "HTTP session create. timeout chan=%p ses=%d",
161  r->timeout_iochan, service->session_timeout);
163 
164  iochan_add(service->server->iochan_man, r->timeout_iochan, -1);
165  http_session_use(1);
166  return r;
167 }
168 
170 {
171  int must_destroy = 0;
172 
174 
176  "HTTP session destroy");
177  yaz_mutex_enter(http_sessions->mutex);
178  /* only if http_session has no active http sessions on it can be destroyed */
179  if (s->destroy_counter == s->activity_counter)
180  {
181  struct http_session **p = 0;
182  must_destroy = 1;
183  for (p = &http_sessions->session_list; *p; p = &(*p)->next)
184  if (*p == s)
185  {
186  *p = (*p)->next;
187  break;
188  }
189  }
190  yaz_mutex_leave(http_sessions->mutex);
191  if (must_destroy)
192  { /* destroying for real */
193  session_log(s->psession, http_sessions->log_level, "About to destroyd");
196  http_session_use(-1);
197  nmem_destroy(s->nmem);
198  }
199  else
200  {
202  "Destroy delayed. Active clients (%d-%d)",
204  }
205 
206 }
207 
208 static const char *get_msg(enum pazpar2_error_code code)
209 {
210  struct pazpar2_error_msg {
211  enum pazpar2_error_code code;
212  const char *msg;
213  };
214  static const struct pazpar2_error_msg ar[] = {
215  { PAZPAR2_NO_SESSION, "Session does not exist or it has expired"},
216  { PAZPAR2_MISSING_PARAMETER, "Missing parameter"},
217  { PAZPAR2_MALFORMED_PARAMETER_VALUE, "Malformed parameter value"},
218  { PAZPAR2_MALFORMED_PARAMETER_ENCODING, "Malformed parameter encoding"},
219  { PAZPAR2_MALFORMED_SETTING, "Malformed setting argument"},
220  { PAZPAR2_HITCOUNTS_FAILED, "Failed to retrieve hitcounts"},
221  { PAZPAR2_RECORD_MISSING, "Record missing"},
222  { PAZPAR2_NO_TARGETS, "No targets"},
223  { PAZPAR2_CONFIG_TARGET, "Target cannot be configured"},
224  { PAZPAR2_RECORD_FAIL, "Record command failed"},
225  { PAZPAR2_NOT_IMPLEMENTED, "Not implemented"},
226  { PAZPAR2_NO_SERVICE, "No service"},
227  { PAZPAR2_ALREADY_BLOCKED, "Already blocked in session on: "},
228  { PAZPAR2_LAST_ERROR, "Last error"},
229  { 0, 0 }
230  };
231  int i = 0;
232  while (ar[i].msg)
233  {
234  if (code == ar[i].code)
235  return ar[i].msg;
236  i++;
237  }
238  return "No error";
239 }
240 
241 static void error2(struct http_response *rs,
242  enum pazpar2_error_code code,
243  const char *addinfo, const char *addinfo2)
244 {
245  struct http_channel *c = rs->channel;
246  WRBUF text = wrbuf_alloc();
247  const char *http_status = "417";
248  const char *msg = get_msg(code);
249 
250  rs->msg = nmem_strdup(c->nmem, msg);
251  strcpy(rs->code, http_status);
252 
253  wrbuf_printf(text, HTTP_COMMAND_RESPONSE_PREFIX
254  "<error code=\"%d\" msg=\"%s\">", (int) code, msg);
255  if (addinfo)
256  {
257  wrbuf_xmlputs(text, addinfo);
258  if (addinfo2)
259  {
260  wrbuf_xmlputs(text, ": ");
261  wrbuf_xmlputs(text, addinfo2);
262  }
263  }
264  wrbuf_puts(text, "</error>");
265 
266  yaz_log(YLOG_WARN, "HTTP %s %s%s%s", http_status,
267  msg, addinfo ? ": " : "" , addinfo ? addinfo : "");
268  rs->payload = nmem_strdup(c->nmem, wrbuf_cstr(text));
269  wrbuf_destroy(text);
271 }
272 
273 static void error(struct http_response *rs,
274  enum pazpar2_error_code code,
275  const char *addinfo)
276 {
277  error2(rs, code, addinfo, 0);
278 }
279 
280 static void response_open_command(struct http_channel *c, const char *command)
281 {
282  wrbuf_rewind(c->wrbuf);
283  wrbuf_puts(c->wrbuf, HTTP_COMMAND_RESPONSE_PREFIX);
284  if (command)
285  wrbuf_printf(c->wrbuf, "<%s>", command);
286 }
287 
288 static void response_open_ok(struct http_channel *c, const char *command)
289 {
290  response_open_command(c, command);
291  wrbuf_puts(c->wrbuf, "<status>OK</status>");
292 }
293 
294 static void response_close(struct http_channel *c, const char *command)
295 {
296  struct http_response *rs = c->response;
297 
298  if (command)
299  wrbuf_printf(c->wrbuf, "</%s>", command);
300  rs->payload = nmem_strdup(c->nmem, wrbuf_cstr(c->wrbuf));
302 }
303 
304 unsigned int make_sessionid(void)
305 {
306  static int seq = 0; /* thread pr */
307  unsigned int res;
308 
309  seq++;
311  res = seq;
312  else
313  {
314 #ifdef WIN32
315  res = seq;
316 #else
317  struct timeval t;
318 
319  if (gettimeofday(&t, 0) < 0)
320  {
321  yaz_log(YLOG_WARN|YLOG_ERRNO, "gettimeofday");
322  exit(1);
323  }
324  /* at most 256 sessions per second ..
325  (long long would be more appropriate)*/
326  res = t.tv_sec;
327  res = ((res << 8) | (seq & 0xff)) & ((1U << 31) - 1);
328 #endif
329  }
330  return res;
331 }
332 
333 static struct http_session *locate_session(struct http_channel *c)
334 {
335  struct http_request *rq = c->request;
336  struct http_response *rs = c->response;
337  struct http_session *p;
338  const char *session = http_argbyname(rq, "session");
340  unsigned int id;
341 
342  if (!session)
343  {
344  error(rs, PAZPAR2_MISSING_PARAMETER, "session");
345  return 0;
346  }
347  id = atoi(session);
348  yaz_mutex_enter(http_sessions->mutex);
349  for (p = http_sessions->session_list; p; p = p->next)
350  if (id == p->session_id)
351  break;
352  if (p)
353  p->activity_counter++;
354  yaz_mutex_leave(http_sessions->mutex);
355  if (p)
357  else
359  return p;
360 }
361 
362 // Call after use of locate_session, in order to increment the destroy_counter
363 static void release_session(struct http_channel *c,
364  struct http_session *session)
365 {
367  yaz_mutex_enter(http_sessions->mutex);
368  if (session)
369  session->destroy_counter++;
370  yaz_mutex_leave(http_sessions->mutex);
371 }
372 
373 // Decode settings parameters and apply to session
374 // Syntax: setting[target]=value
375 static int process_settings(struct session *se, struct http_request *rq,
376  struct http_response *rs)
377 {
378  struct http_argument *a;
379  NMEM nmem = nmem_create();
380 
381  for (a = rq->arguments; a; a = a->next)
382  if (strchr(a->name, '['))
383  {
384  char **res;
385  int num;
386  char *dbname;
387  char *setting;
388 
389  // Nmem_strsplit *rules*!!!
390  nmem_strsplit(nmem, "[]", a->name, &res, &num);
391  if (num != 2)
392  {
394  nmem_destroy(nmem);
395  return -1;
396  }
397  setting = res[0];
398  dbname = res[1];
399  session_apply_setting(se, dbname, setting, a->value);
400  }
401  nmem_destroy(nmem);
402  return 0;
403 }
404 
405 static void cmd_exit(struct http_channel *c)
406 {
407  yaz_log(YLOG_WARN, "exit");
408 
409  response_open_ok(c, "exit");
410  response_close(c, "exit");
413 }
414 
415 static void cmd_init(struct http_channel *c)
416 {
417  struct http_request *r = c->request;
418  const char *clear = http_argbyname(r, "clear");
419  const char *content_type = http_lookup_header(r->headers, "Content-Type");
420  unsigned int sesid;
421  struct http_session *s;
422  struct http_response *rs = c->response;
423  int ignored_content = 0;
424  struct conf_service *service = 0; /* no service (yet) */
425 
426  if (r->content_len && content_type)
427  {
428  if (yaz_strcmp_del("text/xml", content_type, "; "))
429  ignored_content = 1;
430  else
431  {
432  xmlDoc *doc = xmlParseMemory(r->content_buf, r->content_len);
433  xmlNode *root_n;
434  if (!doc)
435  {
437  return;
438  }
439  root_n = xmlDocGetRootElement(doc);
440  service = service_create(c->server, root_n);
441  xmlFreeDoc(doc);
442  if (!service)
443  {
445  return;
446  }
447  }
448  }
449  if (!service)
450  {
451  const char *service_name = http_argbyname(c->request, "service");
452  service = locate_service(c->server, service_name);
453  if (!service)
454  {
455  error(rs, PAZPAR2_NO_SERVICE, service_name ? service_name : "unnamed");
456  return;
457  }
458  }
459  sesid = make_sessionid();
460  s = http_session_create(service, c->http_sessions, sesid);
461 
462  if (ignored_content)
463  session_log(s->psession, YLOG_WARN,
464  "Ignoring content (Content-Type must be text/xml)");
465  if (!clear || *clear == '0')
467  else
468  session_log(s->psession, YLOG_LOG, "No databases preloaded");
469 
470  if (process_settings(s->psession, c->request, c->response) < 0)
471  return;
472 
473  response_open_ok(c, "init");
474  wrbuf_printf(c->wrbuf, "<session>%d", sesid);
475  if (c->server->server_id)
476  {
477  wrbuf_puts(c->wrbuf, ".");
478  wrbuf_puts(c->wrbuf, c->server->server_id);
479  }
480  wrbuf_puts(c->wrbuf, "</session>"
481  "<protocol>" PAZPAR2_PROTOCOL_VERSION "</protocol>");
482 
483  wrbuf_printf(c->wrbuf, "<keepAlive>%d</keepAlive>\n",
484  1000 * ((s->psession->service->session_timeout >= 20) ?
485  (s->psession->service->session_timeout - 10) : 50));
486  response_close(c, "init");
487 }
488 
489 static void apply_local_setting(void *client_data,
490  struct setting *set)
491 {
492  struct session *se = (struct session *) client_data;
493 
494  session_apply_setting(se, set->target, set->name, set->value);
495 }
496 
497 static void cmd_settings(struct http_channel *c)
498 {
499  struct http_response *rs = c->response;
500  struct http_request *rq = c->request;
501  struct http_session *s = locate_session(c);
502  const char *content_type = http_lookup_header(rq->headers, "Content-Type");
503 
504  if (!s)
505  return;
506 
507  if (rq->content_len && content_type)
508  {
509  if (yaz_strcmp_del("text/xml", content_type, "; "))
510  {
511  session_log(s->psession, YLOG_WARN,
512  "Ignoring content (Content-Type must be text/xml)");
513  }
514  else
515  {
516  xmlDoc *doc = xmlParseMemory(rq->content_buf, rq->content_len);
517  xmlNode *root_n;
518  int ret;
519  if (!doc)
520  {
522  release_session(c, s);
523  return;
524  }
525  root_n = xmlDocGetRootElement(doc);
527  xmlFreeDoc(doc);
528  if (ret)
529  {
531  release_session(c, s);
532  return;
533  }
534  }
535  }
536  if (process_settings(s->psession, rq, rs) < 0)
537  {
538  release_session(c, s);
539  return;
540  }
541  response_open_ok(c, "settings");
542  response_close(c, "settings");
543  release_session(c, s);
544 }
545 
546 static void termlist_response(struct http_channel *c, struct http_session *s,
547  const char *cmd_status)
548 {
549  struct http_request *rq = c->request;
550  const char *name = http_argbyname(rq, "name");
551  const char *nums = http_argbyname(rq, "num");
552  int version = get_version(rq);
553  int num = 15;
554  int status;
555 
556  if (nums)
557  num = atoi(nums);
558 
559  status = session_active_clients(s->psession);
560 
561  response_open_command(c, "termlist");
562  /* new protocol add a status to response. Triggered by a status parameter */
563  if (cmd_status != 0)
564  wrbuf_printf(c->wrbuf, "<status>%s</status>\n", cmd_status);
565  wrbuf_printf(c->wrbuf, "<activeclients>%d</activeclients>\n", status);
566 
567  perform_termlist(c, s->psession, name, num, version);
568 
569  response_close(c, "termlist");
570 }
571 
572 static void termlist_result_ready(void *data)
573 {
574  struct http_channel *c = (struct http_channel *) data;
575  struct http_request *rq = c->request;
576  const char *report = http_argbyname(rq, "report");
577  const char *status = 0;
578  struct http_session *s = locate_session(c);
579  if (report && !strcmp("status", report))
580  status = "OK";
581  if (s)
582  {
584  "termlist watch released");
585  termlist_response(c, s, status);
586  release_session(c, s);
587  }
588 }
589 
590 static void cmd_termlist(struct http_channel *c)
591 {
592  struct http_request *rq = c->request;
593  struct http_response *rs = c->response;
594  struct http_session *s = locate_session(c);
595  const char *block = http_argbyname(rq, "block");
596  const char *report = http_argbyname(rq, "report");
597  int report_status = 0;
598  int report_error = 0;
599  const char *status_message = 0;
600  int active_clients;
601 
602  if (report && !strcmp("error", report))
603  {
604  report_error = 1;
605  status_message = "OK";
606  }
607  if (report && !strcmp("status", report))
608  {
609  report_status = 1;
610  status_message = "OK";
611  }
612  if (!s)
613  return;
614 
615  active_clients = session_active_clients(s->psession);
616  if (block && !strcmp("1", block) && active_clients)
617  {
618  // if there is already a watch/block. we do not block this one
620  termlist_result_ready, c, c) != 0)
621  {
622  session_log(s->psession, YLOG_WARN, "Attempt to block "
623  "multiple times on termlist block. Not supported!");
624  if (report_error) {
625  error(rs, PAZPAR2_ALREADY_BLOCKED, "termlist");
626  release_session(c, s);
627  return;
628  }
629  else if (report_status)
630  status_message = "WARNING (Already blocked on termlist)";
631  else
632  session_log(s->psession, YLOG_WARN,
633  "Ignoring termlist block. Return current result");
634  }
635  else
636  {
638  "Blocking on command termlist");
639  release_session(c, s);
640  return;
641  }
642  }
643 
644  termlist_response(c, s, status_message);
645  release_session(c, s);
646 }
647 
649 
650 static void session_status(struct http_channel *c, struct http_session *s)
651 {
652  size_t session_nmem;
653  wrbuf_printf(c->wrbuf, "<http_count>%u</http_count>\n",
654  s->activity_counter);
655  wrbuf_printf(c->wrbuf, "<http_nmem>%zu</http_nmem>\n",
656  nmem_total(s->nmem) );
657  session_nmem = session_get_memory_status(s->psession);
658  wrbuf_printf(c->wrbuf, "<session_nmem>%zu</session_nmem>\n", session_nmem);
659 }
660 
661 static void cmd_service(struct http_channel *c)
662 {
663  struct http_session *s = locate_session(c);
664  if (!s)
665  return;
666 
667  response_open_command(c, 0);
668  if (s->psession->service->xml_node)
669  wrbuf_puts(c->wrbuf, s->psession->service->xml_node);
670  response_close(c, 0);
671  release_session(c, s);
672 }
673 
674 static void cmd_session_status(struct http_channel *c)
675 {
676  struct http_session *s = locate_session(c);
677  if (!s)
678  return;
679 
680  response_open_ok(c, "session-status");
681  session_status(c, s);
682  response_close(c, "session-status");
683  release_session(c, s);
684 }
685 
686 static void bytarget_response(struct http_channel *c, struct http_session *s,
687  const char *cmd_status)
688 {
689  int count, i;
690  struct http_request *rq = c->request;
691  const char *settings = http_argbyname(rq, "settings");
692  int version = get_version(rq);
693  struct hitsbytarget *ht = get_hitsbytarget(s->psession, &count, c->nmem);
694 
695  if (!cmd_status)
696  /* Old protocol, always ok */
697  response_open_ok(c, "bytarget");
698  else
699  {
700  /* New protocol, OK or WARNING (...)*/
701  response_open_command(c, "bytarget");
702  wrbuf_printf(c->wrbuf, "<status>%s</status>", cmd_status);
703  }
704 
705  if (count == 0)
706  session_log(s->psession, YLOG_WARN,
707  "Empty bytarget Response. No targets found!");
708  for (i = 0; i < count; i++)
709  {
710  wrbuf_puts(c->wrbuf, "\n<target>");
711 
712  wrbuf_puts(c->wrbuf, "<id>");
713  wrbuf_xmlputs(c->wrbuf, ht[i].id);
714  wrbuf_puts(c->wrbuf, "</id>\n");
715 
716  if (ht[i].name && ht[i].name[0])
717  {
718  wrbuf_puts(c->wrbuf, "<name>");
719  wrbuf_xmlputs(c->wrbuf, ht[i].name);
720  wrbuf_puts(c->wrbuf, "</name>\n");
721  }
722 
723  wrbuf_printf(c->wrbuf, "<hits>" ODR_INT_PRINTF "</hits>\n", ht[i].hits);
724  wrbuf_printf(c->wrbuf, "<diagnostic>%d</diagnostic>\n",
725  ht[i].diagnostic);
726  if (ht[i].diagnostic)
727  {
728  wrbuf_puts(c->wrbuf, "<message>");
729  wrbuf_xmlputs(c->wrbuf, ht[i].message);
730  wrbuf_puts(c->wrbuf, "</message>\n");
731  wrbuf_puts(c->wrbuf, "<addinfo>");
732  if (ht[i].addinfo)
733  wrbuf_xmlputs(c->wrbuf, ht[i].addinfo);
734  wrbuf_puts(c->wrbuf, "</addinfo>\n");
735  }
736 
737  wrbuf_printf(c->wrbuf, "<records>%d</records>\n",
738  ht[i].records - ht[i].filtered);
739  wrbuf_printf(c->wrbuf, "<filtered>%d</filtered>\n", ht[i].filtered);
740  if (version >= 2)
741  {
742  wrbuf_printf(c->wrbuf, "<approximation>" ODR_INT_PRINTF
743  "</approximation>\n", ht[i].approximation);
744  }
745  wrbuf_puts(c->wrbuf, "<state>");
746  wrbuf_xmlputs(c->wrbuf, ht[i].state);
747  wrbuf_puts(c->wrbuf, "</state>\n");
748  if (settings && *settings == '1')
749  {
750  wrbuf_puts(c->wrbuf, "<settings>\n");
751  wrbuf_puts(c->wrbuf, ht[i].settings_xml);
752  wrbuf_puts(c->wrbuf, "</settings>\n");
753  }
754  if (ht[i].suggestions_xml && ht[i].suggestions_xml[0])
755  {
756  wrbuf_puts(c->wrbuf, "<suggestions>");
757  wrbuf_puts(c->wrbuf, ht[i].suggestions_xml);
758  wrbuf_puts(c->wrbuf, "</suggestions>");
759  }
760  if (ht[i].query_data)
761  {
762  wrbuf_puts(c->wrbuf, "<query_type>");
763  wrbuf_xmlputs(c->wrbuf, ht[i].query_type);
764  wrbuf_puts(c->wrbuf, "</query_type>\n");
765  wrbuf_puts(c->wrbuf, "<query_data>");
766  wrbuf_xmlputs(c->wrbuf, ht[i].query_data);
767  wrbuf_puts(c->wrbuf, "</query_data>\n");
768  }
769  wrbuf_puts(c->wrbuf, "</target>");
770  }
771  response_close(c, "bytarget");
772 }
773 
774 static void bytarget_result_ready(void *data)
775 {
776  struct http_channel *c = (struct http_channel *) data;
777  struct http_session *s = locate_session(c);
778  const char *status_message = "OK";
779  if (s)
780  {
782  "bytarget watch released");
783  bytarget_response(c, s, status_message);
784  release_session(c, s);
785  }
786  else
787  yaz_log(c->http_sessions->log_level,
788  "No Session found for released bytarget watch");
789 }
790 
791 
792 static void cmd_bytarget(struct http_channel *c)
793 {
794  struct http_request *rq = c->request;
795  struct http_response *rs = c->response;
796  struct http_session *s = locate_session(c);
797  const char *block = http_argbyname(rq, "block");
798  const char *report = http_argbyname(rq, "report");
799  int report_error = 0;
800  int report_status = 0;
801  const char *status_message = "OK";
802  int no_active;
803 
804  if (report && !strcmp("error", report))
805  report_error = 1;
806  if (report && !strcmp("status", report))
807  report_status = 1;
808 
809  if (!s)
810  return;
811 
812  no_active = session_active_clients(s->psession);
813  if (block && !strcmp("1", block) && no_active)
814  {
815  // if there is already a watch/block. we do not block this one
817  bytarget_result_ready, c, c) != 0)
818  {
819  session_log(s->psession, YLOG_WARN, "Attempt to block "
820  "multiple times on bytarget block. Not supported!");
821  if (report_error)
822  {
823  error(rs, PAZPAR2_ALREADY_BLOCKED, "bytarget");
824  release_session(c, s);
825  return;
826  }
827  else if (report_status)
828  status_message = "WARNING (Already blocked on bytarget)";
829  else
830  session_log(s->psession, YLOG_WARN, "Ignoring bytarget block."
831  " Return current result.");
832  }
833  else
834  {
836  "Blocking on command bytarget");
837  release_session(c, s);
838  return;
839  }
840  }
841  bytarget_response(c, s, status_message);
842  release_session(c, s);
843 }
844 
845 static void write_metadata(WRBUF w, struct conf_service *service,
846  struct record_metadata **ml, unsigned flags,
847  int indent)
848 {
849  int imeta;
850 
851  for (imeta = 0; imeta < service->num_metadata; imeta++)
852  {
853  struct conf_metadata *cmd = &service->metadata[imeta];
854  struct record_metadata *md;
855  if (!cmd->brief && !(flags & 1))
856  continue;
857  for (md = ml[imeta]; md; md = md->next)
858  {
859  struct record_metadata_attr *attr = md->attributes;
860  int i;
861  for (i = 0; i < indent; i++)
862  wrbuf_putc(w, ' ');
863  wrbuf_printf(w, "<md-%s", cmd->name);
864 
865  for (; attr; attr = attr->next)
866  {
867  wrbuf_printf(w, " %s=\"", attr->name);
868  wrbuf_xmlputs(w, attr->value);
869  wrbuf_puts(w, "\"");
870  }
871  wrbuf_puts(w, ">");
872  switch (cmd->type)
873  {
875  if (md->data.text.snippet && (flags & 2))
876  wrbuf_puts(w, md->data.text.snippet);
877  else
878  wrbuf_xmlputs(w, md->data.text.disp);
879  break;
880  case Metadata_type_year:
881  wrbuf_printf(w, "%d", md->data.number.min);
882  if (md->data.number.min != md->data.number.max)
883  wrbuf_printf(w, "-%d", md->data.number.max);
884  break;
885  case Metadata_type_float:
886  wrbuf_printf(w, "%f", md->data.fnumber);
887  break;
888  default:
889  wrbuf_puts(w, "[can't represent]");
890  break;
891  }
892  wrbuf_printf(w, "</md-%s>\n", cmd->name);
893  }
894  }
895 }
896 
897 static void write_subrecord(struct record *r, WRBUF w,
898  struct conf_service *service, unsigned flags,
899  int indent)
900 {
901  const char *name = session_setting_oneval(
903 
904  wrbuf_puts(w, " <location id=\"");
905  wrbuf_xmlputs(w, client_get_id(r->client));
906  wrbuf_puts(w, "\"\n");
907 
908  wrbuf_puts(w, " name=\"");
909  wrbuf_xmlputs(w, *name ? name : "Unknown");
910  wrbuf_puts(w, "\" ");
911 
912  wrbuf_puts(w, "checksum=\"");
913  wrbuf_printf(w, "%u", r->checksum);
914  wrbuf_puts(w, "\">\n");
915 
916  write_metadata(w, service, r->metadata, flags, indent);
917  wrbuf_puts(w, " </location>\n");
918 }
919 
920 static void show_raw_record_error(void *data, const char *addinfo)
921 {
922  http_channel_observer_t obs = data;
923  struct http_channel *c = http_channel_observer_chan(obs);
924  struct http_response *rs = c->response;
925 
927 
928  error(rs, PAZPAR2_RECORD_FAIL, addinfo);
929 }
930 
931 static void show_raw_record_ok(void *data, const char *buf, size_t sz)
932 {
933  http_channel_observer_t obs = data;
934  struct http_channel *c = http_channel_observer_chan(obs);
935  struct http_response *rs = c->response;
936 
938 
939  wrbuf_write(c->wrbuf, buf, sz);
940  rs->payload = nmem_strdup(c->nmem, wrbuf_cstr(c->wrbuf));
942 }
943 
944 
945 static void show_raw_record_ok_binary(void *data, const char *buf, size_t sz)
946 {
947  http_channel_observer_t obs = data;
948  struct http_channel *c = http_channel_observer_chan(obs);
949  struct http_response *rs = c->response;
950 
952 
953  wrbuf_write(c->wrbuf, buf, sz);
954  rs->payload = nmem_strdup(c->nmem, wrbuf_cstr(c->wrbuf));
955 
956  rs->content_type = "application/octet-stream";
958 }
959 
960 
961 void show_raw_reset(void *data, struct http_channel *c, void *data2)
962 {
963  //struct client *client = data;
964  //client_show_raw_remove(client, data2);
965 }
966 
967 static void cmd_record_ready(void *data);
968 
969 static void show_record(struct http_channel *c, struct http_session *s)
970 {
971  struct http_response *rs = c->response;
972  struct http_request *rq = c->request;
973  struct record_cluster *rec, *prev_r, *next_r;
974  struct conf_service *service;
975  const char *idstr = http_argbyname(rq, "id");
976  const char *offsetstr = http_argbyname(rq, "offset");
977  const char *binarystr = http_argbyname(rq, "binary");
978  const char *checksumstr = http_argbyname(rq, "checksum");
979  const char *snippets = http_argbyname(rq, "snippets");
980  unsigned flags = (snippets && *snippets == '1') ? 3 : 1;
981 
982  if (!s)
983  return;
984  service = s->psession->service;
985  if (!idstr)
986  {
987  error(rs, PAZPAR2_MISSING_PARAMETER, "id");
988  return;
989  }
990  wrbuf_rewind(c->wrbuf);
991  if (!(rec = show_single_start(s->psession, idstr, &prev_r, &next_r)))
992  {
993  if (session_active_clients(s->psession) == 0)
994  {
995  error(rs, PAZPAR2_RECORD_MISSING, idstr);
996  }
998  cmd_record_ready, c, c) != 0)
999  {
1000  error(rs, PAZPAR2_RECORD_MISSING, idstr);
1001  }
1002  return;
1003  }
1004  if (offsetstr || checksumstr)
1005  {
1006  const char *syntax = http_argbyname(rq, "syntax");
1007  const char *esn = http_argbyname(rq, "esn");
1008  int i;
1009  struct record*r = rec->records;
1010  int binary = 0;
1011  const char *nativesyntax = http_argbyname(rq, "nativesyntax");
1012 
1013  if (binarystr && *binarystr != '0')
1014  binary = 1;
1015 
1016  if (checksumstr)
1017  {
1018  unsigned v = strtoul(checksumstr, 0, 10);
1019  for (i = 0; r; r = r->next)
1020  if (v == r->checksum)
1021  break;
1022  if (!r)
1023  error(rs, PAZPAR2_RECORD_FAIL, "no record");
1024  }
1025  else
1026  {
1027  int offset = atoi(offsetstr);
1028  for (i = 0; i < offset && r; r = r->next, i++)
1029  ;
1030  if (!r)
1031  error(rs, PAZPAR2_RECORD_FAIL, "no record at offset given");
1032  }
1033  if (r)
1034  {
1037  int ret = client_show_raw_begin(r->client, r->position,
1038  syntax, esn,
1039  obs /* data */,
1041  (binary ?
1044  (binary ? 1 : 0),
1045  nativesyntax);
1046  if (ret == -1)
1047  {
1048  http_remove_observer(obs);
1049  error(rs, PAZPAR2_NO_SESSION, 0);
1050  }
1051  }
1052  }
1053  else
1054  {
1055  struct record *r;
1056  response_open_command(c, "record");
1057  wrbuf_puts(c->wrbuf, "\n <recid>");
1058  wrbuf_xmlputs(c->wrbuf, rec->recid);
1059  wrbuf_puts(c->wrbuf, "</recid>\n");
1060  if (prev_r)
1061  {
1062  wrbuf_puts(c->wrbuf, " <prevrecid>");
1063  wrbuf_xmlputs(c->wrbuf, prev_r->recid);
1064  wrbuf_puts(c->wrbuf, "</prevrecid>\n");
1065  }
1066  if (next_r)
1067  {
1068  wrbuf_puts(c->wrbuf, " <nextrecid>");
1069  wrbuf_xmlputs(c->wrbuf, next_r->recid);
1070  wrbuf_puts(c->wrbuf, "</nextrecid>\n");
1071  }
1072  wrbuf_printf(c->wrbuf, " <activeclients>%d</activeclients>\n",
1074  write_metadata(c->wrbuf, service, rec->metadata, flags, 1);
1075  for (r = rec->records; r; r = r->next)
1076  write_subrecord(r, c->wrbuf, service, flags, 2);
1077  response_close(c, "record");
1078  }
1079  show_single_stop(s->psession, rec);
1080 }
1081 
1082 static void cmd_record_ready(void *data)
1083 {
1084  struct http_channel *c = (struct http_channel *) data;
1085  struct http_session *s = locate_session(c);
1086  if (s)
1087  {
1089  "record watch released");
1090  show_record(c, s);
1091  release_session(c, s);
1092  }
1093 }
1094 
1095 static void cmd_record(struct http_channel *c)
1096 {
1097  struct http_session *s = locate_session(c);
1098  if (s)
1099  {
1100  show_record(c, s);
1101  release_session(c, s);
1102  }
1103 }
1104 
1105 
1106 static void show_records(struct http_channel *c, struct http_session *s,
1107  int active)
1108 {
1109  struct http_request *rq = c->request;
1110  struct http_response *rs = c->response;
1111  struct record_cluster **rl;
1112  struct reclist_sortparms *sp;
1113  const char *start = http_argbyname(rq, "start");
1114  const char *num = http_argbyname(rq, "num");
1115  const char *sort = http_argbyname(rq, "sort");
1116  int version = get_version(rq);
1117  const char *snippets = http_argbyname(rq, "snippets");
1118  unsigned flags = (snippets && *snippets == '1') ? 2 : 0;
1119 
1120  int startn = 0;
1121  int numn = 20;
1122  int total;
1123  Odr_int total_hits;
1124  Odr_int approx_hits;
1125  int i;
1126  struct conf_service *service = 0;
1127  if (!s)
1128  return;
1129 
1130  // We haven't counted clients yet if we're called on a block release
1131  if (active < 0)
1132  active = session_active_clients(s->psession);
1133 
1134  if (start)
1135  startn = atoi(start);
1136  if (num)
1137  numn = atoi(num);
1138 
1139  service = s->psession->service;
1140  if (!sort)
1141  sort = service->default_sort;
1142  if (!(sp = reclist_parse_sortparms(c->nmem, sort, service)))
1143  {
1145  return;
1146 
1147  }
1148 
1149  rl = show_range_start(s->psession, sp, startn, &numn, &total,
1150  &total_hits, &approx_hits, show_records_ready, c);
1151  if (!rl)
1152  return;
1153 
1154  response_open_ok(c, "show");
1155  wrbuf_printf(c->wrbuf, "\n<activeclients>%d</activeclients>\n", active);
1156  wrbuf_printf(c->wrbuf, "<merged>%d</merged>\n", total);
1157  wrbuf_printf(c->wrbuf, "<total>" ODR_INT_PRINTF "</total>\n", total_hits);
1158  if (version >= 2)
1159  wrbuf_printf(c->wrbuf, "<approximation>" ODR_INT_PRINTF
1160  "</approximation>\n", approx_hits);
1161 
1162  wrbuf_printf(c->wrbuf, "<start>%d</start>\n", startn);
1163  wrbuf_printf(c->wrbuf, "<num>%d</num>\n", numn);
1164 
1165  for (i = 0; i < numn; i++)
1166  {
1167  int ccount;
1168  struct record *p;
1169  struct record_cluster *rec = rl[i];
1170  struct conf_service *service = s->psession->service;
1171 
1172  wrbuf_puts(c->wrbuf, "<hit>\n");
1173  write_metadata(c->wrbuf, service, rec->metadata, flags, 1);
1174  for (ccount = 0, p = rl[i]->records; p; p = p->next, ccount++)
1175  write_subrecord(p, c->wrbuf, service, flags, 2);
1176  wrbuf_printf(c->wrbuf, " <count>%d</count>\n", ccount);
1177  if (strstr(sort, "relevance"))
1178  {
1179  wrbuf_printf(c->wrbuf, " <relevance>%d</relevance>\n",
1180  rec->relevance_score);
1181  if (service->rank_debug)
1182  {
1183  wrbuf_printf(c->wrbuf, " <relevance_info>\n");
1184  wrbuf_xmlputs(c->wrbuf, wrbuf_cstr(rec->relevance_explain1));
1185  wrbuf_xmlputs(c->wrbuf, wrbuf_cstr(rec->relevance_explain2));
1186  wrbuf_printf(c->wrbuf, " </relevance_info>\n");
1187  }
1188  }
1189  wrbuf_puts(c->wrbuf, " <recid>");
1190  wrbuf_xmlputs(c->wrbuf, rec->recid);
1191  wrbuf_puts(c->wrbuf, "</recid>\n");
1192  wrbuf_puts(c->wrbuf, "</hit>\n");
1193  }
1194 
1195  show_range_stop(s->psession, rl);
1196 
1197  response_close(c, "show");
1198 }
1199 
1200 static void show_records_ready(void *data)
1201 {
1202  struct http_channel *c = (struct http_channel *) data;
1203  struct http_session *s = locate_session(c);
1204  if (s)
1205  {
1207  "show watch released");
1208  show_records(c, s, -1);
1209  }
1210  else {
1211  /* some error message */
1212  }
1213  release_session(c, s);
1214 }
1215 
1216 static void cmd_show(struct http_channel *c)
1217 {
1218  struct http_request *rq = c->request;
1219  struct http_response *rs = c->response;
1220  struct http_session *s = locate_session(c);
1221  const char *block = http_argbyname(rq, "block");
1222  const char *sort = http_argbyname(rq, "sort");
1223  const char *block_error = http_argbyname(rq, "report");
1224  const char *mergekey = http_argbyname(rq, "mergekey");
1225  const char *rank = http_argbyname(rq, "rank");
1226  struct conf_service *service = 0;
1227  struct reclist_sortparms *sp;
1228  int status;
1229  int report_error = 0;
1230 
1231  if (block_error && !strcmp("1", block_error))
1232  report_error = 1;
1233  if (!s)
1234  return;
1235  service = s->psession->service;
1236  if (!sort)
1237  sort = service->default_sort;
1238  if (!(sp = reclist_parse_sortparms(c->nmem, sort, service)))
1239  {
1241  release_session(c, s);
1242  return;
1243  }
1244  session_sort(s->psession, sp, mergekey, rank);
1245 
1246  status = session_active_clients(s->psession);
1247 
1248  if (block && reclist_get_num_records(s->psession->reclist) == 0)
1249  {
1250  if (!strcmp(block, "preferred")
1253  {
1254  // if there is already a watch/block. we do not block this one
1256  show_records_ready, c, c) == 0)
1257  {
1259  "Blocking on command show (preferred targets)");
1260  release_session(c, s);
1261  return;
1262  }
1263  else
1264  {
1265  session_log(s->psession, YLOG_WARN, "Attempt to block"
1266  " multiple times on show (preferred targets) block."
1267  " Not supported!");
1268  if (report_error)
1269  {
1271  "show (preferred targets)");
1272  release_session(c, s);
1273  return;
1274  }
1275  else
1276  session_log(s->psession, YLOG_WARN,
1277  "Ignoring show(preferred) block."
1278  " Returning current result");
1279  }
1280 
1281  }
1282  else if (status)
1283  {
1284  // if there is already a watch/block. we do not block this one
1286  show_records_ready, c, c) != 0)
1287  {
1288  session_log(s->psession, YLOG_WARN, "Attempt to block"
1289  " multiple times on show block. Not supported!");
1290  if (report_error)
1291  {
1292  error(rs, PAZPAR2_ALREADY_BLOCKED, "show");
1293  release_session(c, s);
1294  return;
1295  }
1296  else
1297  session_log(s->psession, YLOG_WARN, "Ignoring show block."
1298  " Returning current result");
1299  }
1300  else
1301  {
1303  "Blocking on command show");
1304  release_session(c, s);
1305  return;
1306  }
1307  }
1308  }
1309  show_records(c, s, status);
1310  release_session(c, s);
1311 }
1312 
1313 static void cmd_ping(struct http_channel *c)
1314 {
1315  struct http_session *s = locate_session(c);
1316  if (!s)
1317  return;
1318  response_open_ok(c, "ping");
1319  response_close(c, "ping");
1320  release_session(c, s);
1321 }
1322 
1323 static void cmd_search(struct http_channel *c)
1324 {
1325  struct http_request *rq = c->request;
1326  struct http_response *rs = c->response;
1327  struct http_session *s = locate_session(c);
1328  const char *query = http_argbyname(rq, "query");
1329  const char *filter = http_argbyname(rq, "filter");
1330  const char *maxrecs = http_argbyname(rq, "maxrecs");
1331  const char *startrecs = http_argbyname(rq, "startrecs");
1332  const char *limit = http_argbyname(rq, "limit");
1333  const char *sort = http_argbyname(rq, "sort");
1334  const char *mergekey = http_argbyname(rq, "mergekey");
1335  const char *rank = http_argbyname(rq, "rank");
1336  enum pazpar2_error_code code;
1337  const char *addinfo = 0;
1338  const char *addinfo2 = 0;
1339  struct reclist_sortparms *sp;
1340  struct conf_service *service = 0;
1341 
1342  if (!s)
1343  return;
1344 
1345  if (!query)
1346  {
1347  error(rs, PAZPAR2_MISSING_PARAMETER, "query");
1348  release_session(c, s);
1349  return;
1350  }
1351  if (!yaz_utf8_check(query))
1352  {
1354  release_session(c, s);
1355  return;
1356  }
1357  service = s->psession->service;
1358  if (!sort)
1359  sort = service->default_sort;
1360 
1361  if (!(sp = reclist_parse_sortparms(c->nmem, sort, s->psession->service)))
1362  {
1364  release_session(c, s);
1365  return;
1366  }
1367 
1368  code = session_search(s->psession, query, startrecs, maxrecs, filter, limit,
1369  &addinfo, &addinfo2, sp, mergekey, rank);
1370  if (code)
1371  {
1372  error2(rs, code, addinfo, addinfo2);
1373  release_session(c, s);
1374  return;
1375  }
1376  response_open_ok(c, "search");
1377  response_close(c, "search");
1378  release_session(c, s);
1379 }
1380 
1381 
1382 static void cmd_stat(struct http_channel *c)
1383 {
1384  struct http_session *s = locate_session(c);
1385  struct statistics stat;
1386  int clients;
1387 
1388  float progress = 0;
1389 
1390  if (!s)
1391  return;
1392 
1393  clients = session_active_clients(s->psession);
1394  statistics(s->psession, &stat);
1395 
1396  if (stat.num_clients > 0)
1397  {
1398  progress = (stat.num_clients - clients) / (float)stat.num_clients;
1399  }
1400 
1401  response_open_command(c, "stat");
1402  wrbuf_printf(c->wrbuf, "\n <activeclients>%d</activeclients>\n", clients);
1403  wrbuf_printf(c->wrbuf, " <hits>" ODR_INT_PRINTF "</hits>\n", stat.num_hits);
1404  wrbuf_printf(c->wrbuf, " <records>%d</records>\n", stat.num_records);
1405  wrbuf_printf(c->wrbuf, " <clients>%d</clients>\n", stat.num_clients);
1406  wrbuf_printf(c->wrbuf, " <unconnected>%d</unconnected>\n", stat.num_no_connection);
1407  wrbuf_printf(c->wrbuf, " <connecting>%d</connecting>\n", stat.num_connecting);
1408  wrbuf_printf(c->wrbuf, " <working>%d</working>\n", stat.num_working);
1409  wrbuf_printf(c->wrbuf, " <idle>%d</idle>\n", stat.num_idle);
1410  wrbuf_printf(c->wrbuf, " <failed>%d</failed>\n", stat.num_failed);
1411  wrbuf_printf(c->wrbuf, " <error>%d</error>\n", stat.num_error);
1412  wrbuf_printf(c->wrbuf, " <progress>%.2f</progress>\n", progress);
1413  response_close(c, "stat");
1414  release_session(c, s);
1415 }
1416 
1417 static void cmd_stop(struct http_channel *c)
1418 {
1419  struct http_session *s = locate_session(c);
1420  if (!s)
1421  return;
1422  response_open_ok(c, "stop");
1423  session_stop(s->psession);
1424  response_close(c, "stop");
1425  release_session(c, s);
1426 }
1427 
1428 static void cmd_info(struct http_channel *c)
1429 {
1430  char yaz_version_str[20];
1431  char yaz_sha1_str[42];
1432 
1433  response_open_command(c, "info");
1434  wrbuf_puts(c->wrbuf, "\n <version>\n");
1435  wrbuf_puts(c->wrbuf, " <pazpar2");
1436 #ifdef PAZPAR2_VERSION_SHA1
1437  wrbuf_printf(c->wrbuf, " sha1=\"%s\"", PAZPAR2_VERSION_SHA1);
1438 #endif
1439  wrbuf_puts(c->wrbuf, ">");
1440  wrbuf_xmlputs(c->wrbuf, VERSION);
1441  wrbuf_puts(c->wrbuf, "</pazpar2>\n");
1442 
1443  yaz_version(yaz_version_str, yaz_sha1_str);
1444  wrbuf_puts(c->wrbuf, " <yaz compiled=\"");
1445  wrbuf_xmlputs(c->wrbuf, YAZ_VERSION);
1446  wrbuf_puts(c->wrbuf, "\" sha1=\"");
1447  wrbuf_xmlputs(c->wrbuf, yaz_sha1_str);
1448  wrbuf_puts(c->wrbuf, "\">");
1449  wrbuf_xmlputs(c->wrbuf, yaz_version_str);
1450  wrbuf_puts(c->wrbuf, "</yaz>\n");
1451 
1452  wrbuf_puts(c->wrbuf, " </version>\n");
1453 #if HAVE_UNISTD_H
1454  {
1455  char hostname_str[64];
1456  if (gethostname(hostname_str, sizeof(hostname_str)) == 0)
1457  {
1458  wrbuf_puts(c->wrbuf, " <host>");
1459  wrbuf_xmlputs(c->wrbuf, hostname_str);
1460  wrbuf_puts(c->wrbuf, "</host>\n");
1461  }
1462  }
1463 #endif
1464  wrbuf_printf(c->wrbuf, " <sessions>%d</sessions>\n", sessions_get_count());
1465  wrbuf_printf(c->wrbuf, " <clients>%d</clients>\n", clients_get_count());
1466  wrbuf_malloc_info(c->wrbuf);
1467  {
1468  char buf[200];
1469  if (nmem_get_status(buf, sizeof(buf) - 1) == 0)
1470  wrbuf_puts(c->wrbuf, buf);
1471  }
1472  info_services(c->server, c->wrbuf);
1473  response_close(c, "info");
1474 }
1475 
1476 struct {
1477  char *name;
1478  void (*fun)(struct http_channel *c);
1479 } commands[] = {
1480  { "init", cmd_init },
1481  { "settings", cmd_settings },
1482  { "stat", cmd_stat },
1483  { "bytarget", cmd_bytarget },
1484  { "show", cmd_show },
1485  { "search", cmd_search },
1486  { "termlist", cmd_termlist },
1487  { "exit", cmd_exit },
1488  { "session-status", cmd_session_status },
1489  { "service", cmd_service },
1490  { "ping", cmd_ping },
1491  { "record", cmd_record },
1492  { "info", cmd_info },
1493  { "stop", cmd_stop },
1494  {0,0}
1495 };
1496 
1498 {
1499  const char *command = http_argbyname(c->request, "command");
1500  struct http_response *rs = http_create_response(c);
1501  int i;
1502 
1503  c->response = rs;
1504 
1505  http_addheader(rs, "Expires", "Thu, 19 Nov 1981 08:52:00 GMT");
1506  http_addheader(rs, "Cache-Control", "no-store, no-cache, must-revalidate, post-check=0, pre-check=0");
1507 
1508  if (!command)
1509  {
1510  error(rs, PAZPAR2_MISSING_PARAMETER, "command");
1511  return;
1512  }
1513  for (i = 0; commands[i].name; i++)
1514  if (!strcmp(commands[i].name, command))
1515  {
1516  (*commands[i].fun)(c);
1517  break;
1518  }
1519  if (!commands[i].name)
1520  error(rs, PAZPAR2_MALFORMED_PARAMETER_VALUE, "command");
1521 
1522  return;
1523 }
1524 
1525 /*
1526  * Local variables:
1527  * c-basic-offset: 4
1528  * c-file-style: "Stroustrup"
1529  * indent-tabs-mode: nil
1530  * End:
1531  * vim: shiftwidth=4 tabstop=8 expandtab
1532  */
1533 
int clients_get_count(void)
Definition: client.c:93
const char * client_get_id(struct client *cl)
Definition: client.c:1833
int client_show_raw_begin(struct client *cl, int position, const char *syntax, const char *esn, void *data, void(*error_handler)(void *data, const char *addinfo), void(*record_handler)(void *data, const char *buf, size_t sz), int binary, const char *nativesyntax)
Definition: client.c:299
struct session_database * client_get_database(struct client *cl)
Definition: client.c:251
Z39.50 client.
#define VERSION
Definition: config.h:74
#define PAZPAR2_VERSION_SHA1
Definition: config.h:68
IOCHAN iochan_create(int fd, IOC_CALLBACK cb, int flags, const char *name)
Definition: eventl.c:209
void iochan_destroy(IOCHAN chan)
Definition: eventl.c:201
int iochan_add(iochan_man_t man, IOCHAN chan, int slack)
Definition: eventl.c:173
#define iochan_settimeout(i, t)
Definition: eventl.h:68
#define iochan_activity(i)
Definition: eventl.h:69
#define iochan_getdata(i)
Definition: eventl.h:62
#define iochan_setdata(i, d)
Definition: eventl.h:63
struct http_response * http_create_response(struct http_channel *c)
Definition: http.c:311
const char * http_lookup_header(struct http_header *header, const char *name)
Definition: http.c:119
void http_remove_observer(http_channel_observer_t obs)
Definition: http.c:1443
const char * http_argbyname(struct http_request *r, const char *name)
Definition: http.c:292
void http_send_response(struct http_channel *ch)
Definition: http.c:844
void http_close_server(struct conf_server *server)
Definition: http.c:1362
void http_addheader(struct http_response *r, const char *name, const char *value)
Definition: http.c:282
http_channel_observer_t http_add_observer(struct http_channel *c, void *data, http_channel_destroy_t des)
Definition: http.c:1430
struct http_channel * http_channel_observer_chan(http_channel_observer_t obs)
Definition: http.c:1455
static struct http_session * locate_session(struct http_channel *c)
Definition: http_command.c:333
static void cmd_record(struct http_channel *c)
int http_session_use(int delta)
Definition: http_command.c:83
static void bytarget_result_ready(void *data)
Definition: http_command.c:774
http_sessions_t http_sessions_create(void)
Definition: http_command.c:98
int get_version(struct http_request *rq)
Definition: http_command.c:73
void http_session_destroy(struct http_session *s)
Definition: http_command.c:169
static void cmd_record_ready(void *data)
static void show_raw_record_ok_binary(void *data, const char *buf, size_t sz)
Definition: http_command.c:945
static void apply_local_setting(void *client_data, struct setting *set)
Definition: http_command.c:489
static void error2(struct http_response *rs, enum pazpar2_error_code code, const char *addinfo, const char *addinfo2)
Definition: http_command.c:241
static void termlist_result_ready(void *data)
Definition: http_command.c:572
static void show_record(struct http_channel *c, struct http_session *s)
Definition: http_command.c:969
void(* fun)(struct http_channel *c)
static void cmd_ping(struct http_channel *c)
#define PAZPAR2_PROTOCOL_VERSION
Definition: http_command.c:46
static void cmd_bytarget(struct http_channel *c)
Definition: http_command.c:792
struct http_session * http_session_create(struct conf_service *service, http_sessions_t http_sessions, unsigned int sesid)
Definition: http_command.c:134
void http_sessions_destroy(http_sessions_t hs)
Definition: http_command.c:108
char * name
static void session_timeout(IOCHAN i, int event)
Definition: http_command.c:128
void http_command(struct http_channel *c)
static void termlist_response(struct http_channel *c, struct http_session *s, const char *cmd_status)
Definition: http_command.c:546
static void cmd_termlist(struct http_channel *c)
Definition: http_command.c:590
static void cmd_service(struct http_channel *c)
Definition: http_command.c:661
static void write_subrecord(struct record *r, WRBUF w, struct conf_service *service, unsigned flags, int indent)
Definition: http_command.c:897
static void show_raw_record_ok(void *data, const char *buf, size_t sz)
Definition: http_command.c:931
void show_raw_reset(void *data, struct http_channel *c, void *data2)
Definition: http_command.c:961
static void cmd_settings(struct http_channel *c)
Definition: http_command.c:497
static void response_open_ok(struct http_channel *c, const char *command)
Definition: http_command.c:288
static void cmd_init(struct http_channel *c)
Definition: http_command.c:415
struct @2 commands[]
static void response_close(struct http_channel *c, const char *command)
Definition: http_command.c:294
static void response_open_command(struct http_channel *c, const char *command)
Definition: http_command.c:280
static void cmd_info(struct http_channel *c)
size_t session_get_memory_status(struct session *session)
Definition: session.c:1082
static void cmd_stat(struct http_channel *c)
static void cmd_session_status(struct http_channel *c)
Definition: http_command.c:674
static void cmd_search(struct http_channel *c)
static void release_session(struct http_channel *c, struct http_session *session)
Definition: http_command.c:363
static void error(struct http_response *rs, enum pazpar2_error_code code, const char *addinfo)
Definition: http_command.c:273
static void cmd_stop(struct http_channel *c)
static void bytarget_response(struct http_channel *c, struct http_session *s, const char *cmd_status)
Definition: http_command.c:686
static const char * get_msg(enum pazpar2_error_code code)
Definition: http_command.c:208
#define HTTP_COMMAND_RESPONSE_PREFIX
Definition: http_command.c:48
static int g_http_sessions
Definition: http_command.c:69
static void show_raw_record_error(void *data, const char *addinfo)
Definition: http_command.c:920
static void write_metadata(WRBUF w, struct conf_service *service, struct record_metadata **ml, unsigned flags, int indent)
Definition: http_command.c:845
static int process_settings(struct session *se, struct http_request *rq, struct http_response *rs)
Definition: http_command.c:375
static void show_records_ready(void *data)
static void cmd_exit(struct http_channel *c)
Definition: http_command.c:405
unsigned int make_sessionid(void)
Definition: http_command.c:304
static void cmd_show(struct http_channel *c)
static void show_records(struct http_channel *c, struct http_session *s, int active)
static YAZ_MUTEX g_http_session_mutex
Definition: http_command.c:68
static void session_status(struct http_channel *c, struct http_session *s)
Definition: http_command.c:650
struct parameters global_parameters
Definition: session.c:86
struct conf_service * locate_service(struct conf_server *server, const char *service_id)
void info_services(struct conf_server *server, WRBUF w)
struct conf_service * service_create(struct conf_server *server, xmlNode *node)
@ Metadata_type_float
@ Metadata_type_generic
@ Metadata_type_year
void pazpar2_mutex_create(YAZ_MUTEX *p, const char *name)
Definition: ppmutex.c:39
control MUTEX debugging
struct reclist_sortparms * reclist_parse_sortparms(NMEM nmem, const char *parms, struct conf_service *service)
Definition: reclists.c:71
int reclist_get_num_records(struct reclist *l)
Definition: reclists.c:400
const char * session_setting_oneval(struct session_database *db, int offset)
Definition: session.c:433
enum pazpar2_error_code session_search(struct session *se, const char *query, const char *startrecs, const char *maxrecs, const char *filter, const char *limit, const char **addinfo, const char **addinfo2, struct reclist_sortparms *sp, const char *mergekey, const char *rank)
Definition: session.c:818
void session_stop(struct session *se)
Definition: session.c:791
void session_apply_setting(struct session *se, const char *dbname, const char *name, const char *value)
Definition: session.c:1018
void session_sort(struct session *se, struct reclist_sortparms *sp, const char *mergekey, const char *rank)
Definition: session.c:685
struct session * session_create(NMEM nmem, struct conf_service *service, unsigned session_id)
Definition: session.c:1093
void session_init_databases(struct session *se)
Definition: session.c:987
void show_range_stop(struct session *se, struct record_cluster **recs)
Definition: session.c:1543
int session_set_watch(struct session *s, int what, session_watchfun fun, void *data, struct http_channel *chan)
Definition: session.c:500
void statistics(struct session *se, struct statistics *stat)
Definition: session.c:1548
struct hitsbytarget * get_hitsbytarget(struct session *se, int *count, NMEM nmem)
Definition: session.c:1184
void perform_termlist(struct http_channel *c, struct session *se, const char *name, int num, int version)
Definition: session.c:1259
int sessions_get_count(void)
Definition: session.c:116
struct record_cluster ** show_range_start(struct session *se, struct reclist_sortparms *sp, int start, int *num, int *total, Odr_int *sumhits, Odr_int *approx_hits, void(*show_records_ready)(void *data), struct http_channel *chan)
Definition: session.c:1432
void session_destroy(struct session *se)
Definition: session.c:1053
void show_single_stop(struct session *se, struct record_cluster *rec)
Definition: session.c:1378
void session_log(struct session *s, int level, const char *fmt,...)
Definition: session.c:2509
int session_active_clients(struct session *s)
Definition: session.c:637
int session_is_preferred_clients_ready(struct session *s)
Definition: session.c:649
struct record_cluster * show_single_start(struct session *se, const char *id, struct record_cluster **prev_r, struct record_cluster **next_r)
Definition: session.c:1351
#define SESSION_WATCH_BYTARGET
Definition: session.h:71
pazpar2_error_code
Definition: session.h:36
@ PAZPAR2_MISSING_PARAMETER
Definition: session.h:40
@ PAZPAR2_NO_SERVICE
Definition: session.h:50
@ PAZPAR2_RECORD_FAIL
Definition: session.h:48
@ PAZPAR2_MALFORMED_PARAMETER_VALUE
Definition: session.h:41
@ PAZPAR2_HITCOUNTS_FAILED
Definition: session.h:44
@ PAZPAR2_MALFORMED_PARAMETER_ENCODING
Definition: session.h:42
@ PAZPAR2_NOT_IMPLEMENTED
Definition: session.h:49
@ PAZPAR2_CONFIG_TARGET
Definition: session.h:47
@ PAZPAR2_NO_SESSION
Definition: session.h:39
@ PAZPAR2_ALREADY_BLOCKED
Definition: session.h:51
@ PAZPAR2_LAST_ERROR
Definition: session.h:53
@ PAZPAR2_NO_TARGETS
Definition: session.h:46
@ PAZPAR2_RECORD_MISSING
Definition: session.h:45
@ PAZPAR2_MALFORMED_SETTING
Definition: session.h:43
#define SESSION_WATCH_TERMLIST
Definition: session.h:70
#define SESSION_WATCH_SHOW
Definition: session.h:67
#define SESSION_WATCH_SHOW_PREF
Definition: session.h:69
#define SESSION_WATCH_RECORD
Definition: session.h:68
int settings_read_node_x(xmlNode *n, void *client_data, void(*fun)(void *client_data, struct setting *set))
Definition: settings.c:174
#define PZ_NAME
Definition: settings.h:33
enum conf_metadata_type type
iochan_man_t iochan_man
char * server_id
struct conf_server * server
char * default_sort
struct conf_metadata * metadata
const char * id
Definition: session.h:133
const char * state
Definition: session.h:142
const char * message
Definition: session.h:138
Odr_int approximation
Definition: session.h:136
const char * name
Definition: session.h:134
const char * query_type
Definition: session.h:146
Odr_int hits
Definition: session.h:135
int filtered
Definition: session.h:141
const char * query_data
Definition: session.h:147
int diagnostic
Definition: session.h:137
char * suggestions_xml
Definition: session.h:145
const char * addinfo
Definition: session.h:139
int records
Definition: session.h:140
char * settings_xml
Definition: session.h:144
char * value
Definition: http.h:78
struct http_argument * next
Definition: http.h:79
char * name
Definition: http.h:77
struct http_request * request
Definition: http.h:50
NMEM nmem
Definition: http.h:47
http_sessions_t http_sessions
Definition: http.h:57
struct http_response * response
Definition: http.h:51
WRBUF wrbuf
Definition: http.h:48
struct conf_server * server
Definition: http.h:55
struct http_header * headers
Definition: http.h:91
int content_len
Definition: http.h:90
struct http_argument * arguments
Definition: http.h:92
char * content_buf
Definition: http.h:89
struct http_channel * channel
Definition: http.h:99
char code[4]
Definition: http.h:97
char * content_type
Definition: http.h:102
char * payload
Definition: http.h:101
char * msg
Definition: http.h:98
http_sessions_t http_sessions
Definition: http_command.c:58
unsigned int session_id
Definition: http_command.c:53
int destroy_counter
Definition: http_command.c:55
int activity_counter
Definition: http_command.c:56
struct session * psession
Definition: http_command.c:52
IOCHAN timeout_iochan
Definition: http_command.c:51
struct http_session * next
Definition: http_command.c:59
YAZ_MUTEX mutex
Definition: http_command.c:64
struct http_session * session_list
Definition: http_command.c:63
Definition: eventl.h:32
int debug_mode
Definition: parameters.h:28
int predictable_sessions
Definition: parameters.h:29
struct record_metadata ** metadata
Definition: record.h:87
WRBUF relevance_explain2
Definition: record.h:99
WRBUF relevance_explain1
Definition: record.h:98
int relevance_score
Definition: record.h:92
struct record * records
Definition: record.h:100
char * recid
Definition: record.h:96
struct record_metadata_attr * next
Definition: record.h:45
union data_types data
Definition: record.h:49
struct record_metadata * next
Definition: record.h:51
struct record_metadata_attr * attributes
Definition: record.h:52
Definition: record.h:60
int position
Definition: record.h:69
struct record * next
Definition: record.h:67
struct client * client
Definition: record.h:61
struct record_metadata ** metadata
Definition: record.h:63
unsigned checksum
Definition: record.h:73
struct reclist * reclist
Definition: session.h:101
struct conf_service * service
Definition: session.h:93
const char * name
Definition: settings.h:69
const char * value
Definition: settings.h:70
const char * target
Definition: settings.h:68
int num_connecting
Definition: session.h:123
int num_working
Definition: session.h:124
int num_failed
Definition: session.h:126
int num_clients
Definition: session.h:121
int num_no_connection
Definition: session.h:122
int num_idle
Definition: session.h:125
int num_error
Definition: session.h:127
Odr_int num_hits
Definition: session.h:128
int num_records
Definition: session.h:129
double fnumber
Definition: record.h:38
const char * snippet
Definition: record.h:32
struct data_types::@3 text
int max
Definition: record.h:36
struct data_types::@4 number
const char * disp
Definition: record.h:29
int min
Definition: record.h:35