pazpar2  1.13.0
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);
151  r->next = http_sessions->session_list;
152  http_sessions->session_list = r;
153  yaz_mutex_leave(http_sessions->mutex);
154 
156  "http_session_timeout");
158 
159  session_log(r->psession, http_sessions->log_level,
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 
175  session_log(s->psession, http_sessions->log_level,
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  {
201  session_log(s->psession, http_sessions->log_level,
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
358  error(rs, PAZPAR2_NO_SESSION, session);
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  struct conf_service *service = 0; /* no service (yet) */
424 
425  if (r->content_len && content_type &&
426  !yaz_strcmp_del("text/xml", content_type, "; "))
427  {
428  xmlDoc *doc = xmlParseMemory(r->content_buf, r->content_len);
429  xmlNode *root_n;
430  if (!doc)
431  {
433  return;
434  }
435  root_n = xmlDocGetRootElement(doc);
436  service = service_create(c->server, root_n);
437  xmlFreeDoc(doc);
438  if (!service)
439  {
441  return;
442  }
443  }
444 
445  if (!service)
446  {
447  const char *service_name = http_argbyname(c->request, "service");
448  service = locate_service(c->server, service_name);
449  if (!service)
450  {
451  error(rs, PAZPAR2_NO_SERVICE, service_name ? service_name : "unnamed");
452  return;
453  }
454  }
455  sesid = make_sessionid();
456  s = http_session_create(service, c->http_sessions, sesid);
457 
458  if (!clear || *clear == '0')
460  else
461  session_log(s->psession, YLOG_LOG, "No databases preloaded");
462 
463  if (process_settings(s->psession, c->request, c->response) < 0)
464  return;
465 
466  response_open_ok(c, "init");
467  wrbuf_printf(c->wrbuf, "<session>%d", sesid);
468  if (c->server->server_id)
469  {
470  wrbuf_puts(c->wrbuf, ".");
471  wrbuf_puts(c->wrbuf, c->server->server_id);
472  }
473  wrbuf_puts(c->wrbuf, "</session>"
474  "<protocol>" PAZPAR2_PROTOCOL_VERSION "</protocol>");
475 
476  wrbuf_printf(c->wrbuf, "<keepAlive>%d</keepAlive>\n",
477  1000 * ((s->psession->service->session_timeout >= 20) ?
478  (s->psession->service->session_timeout - 10) : 50));
479  response_close(c, "init");
480 }
481 
482 static void apply_local_setting(void *client_data,
483  struct setting *set)
484 {
485  struct session *se = (struct session *) client_data;
486 
487  session_apply_setting(se, set->target, set->name, set->value);
488 }
489 
490 static void cmd_settings(struct http_channel *c)
491 {
492  struct http_response *rs = c->response;
493  struct http_request *rq = c->request;
494  struct http_session *s = locate_session(c);
495  const char *content_type = http_lookup_header(rq->headers, "Content-Type");
496 
497  if (!s)
498  return;
499 
500  if (rq->content_len && content_type &&
501  !yaz_strcmp_del("text/xml", content_type, "; "))
502  {
503  xmlDoc *doc = xmlParseMemory(rq->content_buf, rq->content_len);
504  xmlNode *root_n;
505  int ret;
506  if (!doc)
507  {
509  release_session(c, s);
510  return;
511  }
512  root_n = xmlDocGetRootElement(doc);
514  xmlFreeDoc(doc);
515  if (ret)
516  {
518  release_session(c, s);
519  return;
520  }
521  }
522  if (process_settings(s->psession, rq, rs) < 0)
523  {
524  release_session(c, s);
525  return;
526  }
527  response_open_ok(c, "settings");
528  response_close(c, "settings");
529  release_session(c, s);
530 }
531 
532 static void termlist_response(struct http_channel *c, struct http_session *s,
533  const char *cmd_status)
534 {
535  struct http_request *rq = c->request;
536  const char *name = http_argbyname(rq, "name");
537  const char *nums = http_argbyname(rq, "num");
538  int version = get_version(rq);
539  int num = 15;
540  int status;
541 
542  if (nums)
543  num = atoi(nums);
544 
545  status = session_active_clients(s->psession);
546 
547  response_open_command(c, "termlist");
548  /* new protocol add a status to response. Triggered by a status parameter */
549  if (cmd_status != 0)
550  wrbuf_printf(c->wrbuf, "<status>%s</status>\n", cmd_status);
551  wrbuf_printf(c->wrbuf, "<activeclients>%d</activeclients>\n", status);
552 
553  perform_termlist(c, s->psession, name, num, version);
554 
555  response_close(c, "termlist");
556 }
557 
558 static void termlist_result_ready(void *data)
559 {
560  struct http_channel *c = (struct http_channel *) data;
561  struct http_request *rq = c->request;
562  const char *report = http_argbyname(rq, "report");
563  const char *status = 0;
564  struct http_session *s = locate_session(c);
565  if (report && !strcmp("status", report))
566  status = "OK";
567  if (s)
568  {
570  "termlist watch released");
571  termlist_response(c, s, status);
572  release_session(c, s);
573  }
574 }
575 
576 static void cmd_termlist(struct http_channel *c)
577 {
578  struct http_request *rq = c->request;
579  struct http_response *rs = c->response;
580  struct http_session *s = locate_session(c);
581  const char *block = http_argbyname(rq, "block");
582  const char *report = http_argbyname(rq, "report");
583  int report_status = 0;
584  int report_error = 0;
585  const char *status_message = 0;
586  int active_clients;
587 
588  if (report && !strcmp("error", report))
589  {
590  report_error = 1;
591  status_message = "OK";
592  }
593  if (report && !strcmp("status", report))
594  {
595  report_status = 1;
596  status_message = "OK";
597  }
598  if (!s)
599  return;
600 
601  active_clients = session_active_clients(s->psession);
602  if (block && !strcmp("1", block) && active_clients)
603  {
604  // if there is already a watch/block. we do not block this one
606  termlist_result_ready, c, c) != 0)
607  {
608  session_log(s->psession, YLOG_WARN, "Attempt to block "
609  "multiple times on termlist block. Not supported!");
610  if (report_error) {
611  error(rs, PAZPAR2_ALREADY_BLOCKED, "termlist");
612  release_session(c, s);
613  return;
614  }
615  else if (report_status)
616  status_message = "WARNING (Already blocked on termlist)";
617  else
618  session_log(s->psession, YLOG_WARN,
619  "Ignoring termlist block. Return current result");
620  }
621  else
622  {
624  "Blocking on command termlist");
625  release_session(c, s);
626  return;
627  }
628  }
629 
630  termlist_response(c, s, status_message);
631  release_session(c, s);
632 }
633 
635 
636 static void session_status(struct http_channel *c, struct http_session *s)
637 {
638  size_t session_nmem;
639  wrbuf_printf(c->wrbuf, "<http_count>%u</http_count>\n",
640  s->activity_counter);
641  wrbuf_printf(c->wrbuf, "<http_nmem>%zu</http_nmem>\n",
642  nmem_total(s->nmem) );
643  session_nmem = session_get_memory_status(s->psession);
644  wrbuf_printf(c->wrbuf, "<session_nmem>%zu</session_nmem>\n", session_nmem);
645 }
646 
647 static void cmd_service(struct http_channel *c)
648 {
649  struct http_session *s = locate_session(c);
650  if (!s)
651  return;
652 
653  response_open_command(c, 0);
654  if (s->psession->service->xml_node)
655  wrbuf_puts(c->wrbuf, s->psession->service->xml_node);
656  response_close(c, 0);
657  release_session(c, s);
658 }
659 
660 static void cmd_session_status(struct http_channel *c)
661 {
662  struct http_session *s = locate_session(c);
663  if (!s)
664  return;
665 
666  response_open_ok(c, "session-status");
667  session_status(c, s);
668  response_close(c, "session-status");
669  release_session(c, s);
670 }
671 
672 static void bytarget_response(struct http_channel *c, struct http_session *s,
673  const char *cmd_status)
674 {
675  int count, i;
676  struct http_request *rq = c->request;
677  const char *settings = http_argbyname(rq, "settings");
678  int version = get_version(rq);
679  struct hitsbytarget *ht = get_hitsbytarget(s->psession, &count, c->nmem);
680 
681  if (!cmd_status)
682  /* Old protocol, always ok */
683  response_open_ok(c, "bytarget");
684  else
685  {
686  /* New protocol, OK or WARNING (...)*/
687  response_open_command(c, "bytarget");
688  wrbuf_printf(c->wrbuf, "<status>%s</status>", cmd_status);
689  }
690 
691  if (count == 0)
692  session_log(s->psession, YLOG_WARN,
693  "Empty bytarget Response. No targets found!");
694  for (i = 0; i < count; i++)
695  {
696  wrbuf_puts(c->wrbuf, "\n<target>");
697 
698  wrbuf_puts(c->wrbuf, "<id>");
699  wrbuf_xmlputs(c->wrbuf, ht[i].id);
700  wrbuf_puts(c->wrbuf, "</id>\n");
701 
702  if (ht[i].name && ht[i].name[0])
703  {
704  wrbuf_puts(c->wrbuf, "<name>");
705  wrbuf_xmlputs(c->wrbuf, ht[i].name);
706  wrbuf_puts(c->wrbuf, "</name>\n");
707  }
708 
709  wrbuf_printf(c->wrbuf, "<hits>" ODR_INT_PRINTF "</hits>\n", ht[i].hits);
710  wrbuf_printf(c->wrbuf, "<diagnostic>%d</diagnostic>\n",
711  ht[i].diagnostic);
712  if (ht[i].diagnostic)
713  {
714  wrbuf_puts(c->wrbuf, "<message>");
715  wrbuf_xmlputs(c->wrbuf, ht[i].message);
716  wrbuf_puts(c->wrbuf, "</message>\n");
717  wrbuf_puts(c->wrbuf, "<addinfo>");
718  if (ht[i].addinfo)
719  wrbuf_xmlputs(c->wrbuf, ht[i].addinfo);
720  wrbuf_puts(c->wrbuf, "</addinfo>\n");
721  }
722 
723  wrbuf_printf(c->wrbuf, "<records>%d</records>\n",
724  ht[i].records - ht[i].filtered);
725  wrbuf_printf(c->wrbuf, "<filtered>%d</filtered>\n", ht[i].filtered);
726  if (version >= 2)
727  {
728  wrbuf_printf(c->wrbuf, "<approximation>" ODR_INT_PRINTF
729  "</approximation>\n", ht[i].approximation);
730  }
731  wrbuf_puts(c->wrbuf, "<state>");
732  wrbuf_xmlputs(c->wrbuf, ht[i].state);
733  wrbuf_puts(c->wrbuf, "</state>\n");
734  if (settings && *settings == '1')
735  {
736  wrbuf_puts(c->wrbuf, "<settings>\n");
737  wrbuf_puts(c->wrbuf, ht[i].settings_xml);
738  wrbuf_puts(c->wrbuf, "</settings>\n");
739  }
740  if (ht[i].suggestions_xml && ht[i].suggestions_xml[0])
741  {
742  wrbuf_puts(c->wrbuf, "<suggestions>");
743  wrbuf_puts(c->wrbuf, ht[i].suggestions_xml);
744  wrbuf_puts(c->wrbuf, "</suggestions>");
745  }
746  if (ht[i].query_data)
747  {
748  wrbuf_puts(c->wrbuf, "<query_type>");
749  wrbuf_xmlputs(c->wrbuf, ht[i].query_type);
750  wrbuf_puts(c->wrbuf, "</query_type>\n");
751  wrbuf_puts(c->wrbuf, "<query_data>");
752  wrbuf_xmlputs(c->wrbuf, ht[i].query_data);
753  wrbuf_puts(c->wrbuf, "</query_data>\n");
754  }
755  wrbuf_puts(c->wrbuf, "</target>");
756  }
757  response_close(c, "bytarget");
758 }
759 
760 static void bytarget_result_ready(void *data)
761 {
762  struct http_channel *c = (struct http_channel *) data;
763  struct http_session *s = locate_session(c);
764  const char *status_message = "OK";
765  if (s)
766  {
768  "bytarget watch released");
769  bytarget_response(c, s, status_message);
770  release_session(c, s);
771  }
772  else
773  yaz_log(c->http_sessions->log_level,
774  "No Session found for released bytarget watch");
775 }
776 
777 
778 static void cmd_bytarget(struct http_channel *c)
779 {
780  struct http_request *rq = c->request;
781  struct http_response *rs = c->response;
782  struct http_session *s = locate_session(c);
783  const char *block = http_argbyname(rq, "block");
784  const char *report = http_argbyname(rq, "report");
785  int report_error = 0;
786  int report_status = 0;
787  const char *status_message = "OK";
788  int no_active;
789 
790  if (report && !strcmp("error", report))
791  report_error = 1;
792  if (report && !strcmp("status", report))
793  report_status = 1;
794 
795  if (!s)
796  return;
797 
798  no_active = session_active_clients(s->psession);
799  if (block && !strcmp("1", block) && no_active)
800  {
801  // if there is already a watch/block. we do not block this one
803  bytarget_result_ready, c, c) != 0)
804  {
805  session_log(s->psession, YLOG_WARN, "Attempt to block "
806  "multiple times on bytarget block. Not supported!");
807  if (report_error)
808  {
809  error(rs, PAZPAR2_ALREADY_BLOCKED, "bytarget");
810  release_session(c, s);
811  return;
812  }
813  else if (report_status)
814  status_message = "WARNING (Already blocked on bytarget)";
815  else
816  session_log(s->psession, YLOG_WARN, "Ignoring bytarget block."
817  " Return current result.");
818  }
819  else
820  {
822  "Blocking on command bytarget");
823  release_session(c, s);
824  return;
825  }
826  }
827  bytarget_response(c, s, status_message);
828  release_session(c, s);
829 }
830 
831 static void write_metadata(WRBUF w, struct conf_service *service,
832  struct record_metadata **ml, unsigned flags,
833  int indent)
834 {
835  int imeta;
836 
837  for (imeta = 0; imeta < service->num_metadata; imeta++)
838  {
839  struct conf_metadata *cmd = &service->metadata[imeta];
840  struct record_metadata *md;
841  if (!cmd->brief && !(flags & 1))
842  continue;
843  for (md = ml[imeta]; md; md = md->next)
844  {
845  struct record_metadata_attr *attr = md->attributes;
846  int i;
847  for (i = 0; i < indent; i++)
848  wrbuf_putc(w, ' ');
849  wrbuf_printf(w, "<md-%s", cmd->name);
850 
851  for (; attr; attr = attr->next)
852  {
853  wrbuf_printf(w, " %s=\"", attr->name);
854  wrbuf_xmlputs(w, attr->value);
855  wrbuf_puts(w, "\"");
856  }
857  wrbuf_puts(w, ">");
858  switch (cmd->type)
859  {
861  if (md->data.text.snippet && (flags & 2))
862  wrbuf_puts(w, md->data.text.snippet);
863  else
864  wrbuf_xmlputs(w, md->data.text.disp);
865  break;
866  case Metadata_type_year:
867  wrbuf_printf(w, "%d", md->data.number.min);
868  if (md->data.number.min != md->data.number.max)
869  wrbuf_printf(w, "-%d", md->data.number.max);
870  break;
871  case Metadata_type_float:
872  wrbuf_printf(w, "%f", md->data.fnumber);
873  break;
874  default:
875  wrbuf_puts(w, "[can't represent]");
876  break;
877  }
878  wrbuf_printf(w, "</md-%s>\n", cmd->name);
879  }
880  }
881 }
882 
883 static void write_subrecord(struct record *r, WRBUF w,
884  struct conf_service *service, unsigned flags,
885  int indent)
886 {
887  const char *name = session_setting_oneval(
889 
890  wrbuf_puts(w, " <location id=\"");
891  wrbuf_xmlputs(w, client_get_id(r->client));
892  wrbuf_puts(w, "\"\n");
893 
894  wrbuf_puts(w, " name=\"");
895  wrbuf_xmlputs(w, *name ? name : "Unknown");
896  wrbuf_puts(w, "\" ");
897 
898  wrbuf_puts(w, "checksum=\"");
899  wrbuf_printf(w, "%u", r->checksum);
900  wrbuf_puts(w, "\">\n");
901 
902  write_metadata(w, service, r->metadata, flags, indent);
903  wrbuf_puts(w, " </location>\n");
904 }
905 
906 static void show_raw_record_error(void *data, const char *addinfo)
907 {
908  http_channel_observer_t obs = data;
909  struct http_channel *c = http_channel_observer_chan(obs);
910  struct http_response *rs = c->response;
911 
913 
914  error(rs, PAZPAR2_RECORD_FAIL, addinfo);
915 }
916 
917 static void show_raw_record_ok(void *data, const char *buf, size_t sz)
918 {
919  http_channel_observer_t obs = data;
920  struct http_channel *c = http_channel_observer_chan(obs);
921  struct http_response *rs = c->response;
922 
924 
925  wrbuf_write(c->wrbuf, buf, sz);
926  rs->payload = nmem_strdup(c->nmem, wrbuf_cstr(c->wrbuf));
928 }
929 
930 
931 static void show_raw_record_ok_binary(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));
941 
942  rs->content_type = "application/octet-stream";
944 }
945 
946 
947 void show_raw_reset(void *data, struct http_channel *c, void *data2)
948 {
949  //struct client *client = data;
950  //client_show_raw_remove(client, data2);
951 }
952 
953 static void cmd_record_ready(void *data);
954 
955 static void show_record(struct http_channel *c, struct http_session *s)
956 {
957  struct http_response *rs = c->response;
958  struct http_request *rq = c->request;
959  struct record_cluster *rec, *prev_r, *next_r;
960  struct conf_service *service;
961  const char *idstr = http_argbyname(rq, "id");
962  const char *offsetstr = http_argbyname(rq, "offset");
963  const char *binarystr = http_argbyname(rq, "binary");
964  const char *checksumstr = http_argbyname(rq, "checksum");
965  const char *snippets = http_argbyname(rq, "snippets");
966  unsigned flags = (snippets && *snippets == '1') ? 3 : 1;
967 
968  if (!s)
969  return;
970  service = s->psession->service;
971  if (!idstr)
972  {
973  error(rs, PAZPAR2_MISSING_PARAMETER, "id");
974  return;
975  }
976  wrbuf_rewind(c->wrbuf);
977  if (!(rec = show_single_start(s->psession, idstr, &prev_r, &next_r)))
978  {
979  if (session_active_clients(s->psession) == 0)
980  {
981  error(rs, PAZPAR2_RECORD_MISSING, idstr);
982  }
984  cmd_record_ready, c, c) != 0)
985  {
986  error(rs, PAZPAR2_RECORD_MISSING, idstr);
987  }
988  return;
989  }
990  if (offsetstr || checksumstr)
991  {
992  const char *syntax = http_argbyname(rq, "syntax");
993  const char *esn = http_argbyname(rq, "esn");
994  int i;
995  struct record*r = rec->records;
996  int binary = 0;
997  const char *nativesyntax = http_argbyname(rq, "nativesyntax");
998 
999  if (binarystr && *binarystr != '0')
1000  binary = 1;
1001 
1002  if (checksumstr)
1003  {
1004  unsigned v = strtoul(checksumstr, 0, 10);
1005  for (i = 0; r; r = r->next)
1006  if (v == r->checksum)
1007  break;
1008  if (!r)
1009  error(rs, PAZPAR2_RECORD_FAIL, "no record");
1010  }
1011  else
1012  {
1013  int offset = atoi(offsetstr);
1014  for (i = 0; i < offset && r; r = r->next, i++)
1015  ;
1016  if (!r)
1017  error(rs, PAZPAR2_RECORD_FAIL, "no record at offset given");
1018  }
1019  if (r)
1020  {
1023  int ret = client_show_raw_begin(r->client, r->position,
1024  syntax, esn,
1025  obs /* data */,
1027  (binary ?
1030  (binary ? 1 : 0),
1031  nativesyntax);
1032  if (ret == -1)
1033  {
1034  http_remove_observer(obs);
1035  error(rs, PAZPAR2_NO_SESSION, 0);
1036  }
1037  }
1038  }
1039  else
1040  {
1041  struct record *r;
1042  response_open_command(c, "record");
1043  wrbuf_puts(c->wrbuf, "\n <recid>");
1044  wrbuf_xmlputs(c->wrbuf, rec->recid);
1045  wrbuf_puts(c->wrbuf, "</recid>\n");
1046  if (prev_r)
1047  {
1048  wrbuf_puts(c->wrbuf, " <prevrecid>");
1049  wrbuf_xmlputs(c->wrbuf, prev_r->recid);
1050  wrbuf_puts(c->wrbuf, "</prevrecid>\n");
1051  }
1052  if (next_r)
1053  {
1054  wrbuf_puts(c->wrbuf, " <nextrecid>");
1055  wrbuf_xmlputs(c->wrbuf, next_r->recid);
1056  wrbuf_puts(c->wrbuf, "</nextrecid>\n");
1057  }
1058  wrbuf_printf(c->wrbuf, " <activeclients>%d</activeclients>\n",
1060  write_metadata(c->wrbuf, service, rec->metadata, flags, 1);
1061  for (r = rec->records; r; r = r->next)
1062  write_subrecord(r, c->wrbuf, service, flags, 2);
1063  response_close(c, "record");
1064  }
1065  show_single_stop(s->psession, rec);
1066 }
1067 
1068 static void cmd_record_ready(void *data)
1069 {
1070  struct http_channel *c = (struct http_channel *) data;
1071  struct http_session *s = locate_session(c);
1072  if (s)
1073  {
1075  "record watch released");
1076  show_record(c, s);
1077  release_session(c, s);
1078  }
1079 }
1080 
1081 static void cmd_record(struct http_channel *c)
1082 {
1083  struct http_session *s = locate_session(c);
1084  if (s)
1085  {
1086  show_record(c, s);
1087  release_session(c, s);
1088  }
1089 }
1090 
1091 
1092 static void show_records(struct http_channel *c, struct http_session *s,
1093  int active)
1094 {
1095  struct http_request *rq = c->request;
1096  struct http_response *rs = c->response;
1097  struct record_cluster **rl;
1098  struct reclist_sortparms *sp;
1099  const char *start = http_argbyname(rq, "start");
1100  const char *num = http_argbyname(rq, "num");
1101  const char *sort = http_argbyname(rq, "sort");
1102  int version = get_version(rq);
1103  const char *snippets = http_argbyname(rq, "snippets");
1104  unsigned flags = (snippets && *snippets == '1') ? 2 : 0;
1105 
1106  int startn = 0;
1107  int numn = 20;
1108  int total;
1109  Odr_int total_hits;
1110  Odr_int approx_hits;
1111  int i;
1112  struct conf_service *service = 0;
1113  if (!s)
1114  return;
1115 
1116  // We haven't counted clients yet if we're called on a block release
1117  if (active < 0)
1118  active = session_active_clients(s->psession);
1119 
1120  if (start)
1121  startn = atoi(start);
1122  if (num)
1123  numn = atoi(num);
1124 
1125  service = s->psession->service;
1126  if (!sort)
1127  sort = service->default_sort;
1128  if (!(sp = reclist_parse_sortparms(c->nmem, sort, service)))
1129  {
1131  return;
1132 
1133  }
1134 
1135  rl = show_range_start(s->psession, sp, startn, &numn, &total,
1136  &total_hits, &approx_hits, show_records_ready, c);
1137  if (!rl)
1138  return;
1139 
1140  response_open_ok(c, "show");
1141  wrbuf_printf(c->wrbuf, "\n<activeclients>%d</activeclients>\n", active);
1142  wrbuf_printf(c->wrbuf, "<merged>%d</merged>\n", total);
1143  wrbuf_printf(c->wrbuf, "<total>" ODR_INT_PRINTF "</total>\n", total_hits);
1144  if (version >= 2)
1145  wrbuf_printf(c->wrbuf, "<approximation>" ODR_INT_PRINTF
1146  "</approximation>\n", approx_hits);
1147 
1148  wrbuf_printf(c->wrbuf, "<start>%d</start>\n", startn);
1149  wrbuf_printf(c->wrbuf, "<num>%d</num>\n", numn);
1150 
1151  for (i = 0; i < numn; i++)
1152  {
1153  int ccount;
1154  struct record *p;
1155  struct record_cluster *rec = rl[i];
1156  struct conf_service *service = s->psession->service;
1157 
1158  wrbuf_puts(c->wrbuf, "<hit>\n");
1159  write_metadata(c->wrbuf, service, rec->metadata, flags, 1);
1160  for (ccount = 0, p = rl[i]->records; p; p = p->next, ccount++)
1161  write_subrecord(p, c->wrbuf, service, flags, 2);
1162  wrbuf_printf(c->wrbuf, " <count>%d</count>\n", ccount);
1163  if (strstr(sort, "relevance"))
1164  {
1165  wrbuf_printf(c->wrbuf, " <relevance>%d</relevance>\n",
1166  rec->relevance_score);
1167  if (service->rank_debug)
1168  {
1169  wrbuf_printf(c->wrbuf, " <relevance_info>\n");
1170  wrbuf_xmlputs(c->wrbuf, wrbuf_cstr(rec->relevance_explain1));
1171  wrbuf_xmlputs(c->wrbuf, wrbuf_cstr(rec->relevance_explain2));
1172  wrbuf_printf(c->wrbuf, " </relevance_info>\n");
1173  }
1174  }
1175  wrbuf_puts(c->wrbuf, " <recid>");
1176  wrbuf_xmlputs(c->wrbuf, rec->recid);
1177  wrbuf_puts(c->wrbuf, "</recid>\n");
1178  wrbuf_puts(c->wrbuf, "</hit>\n");
1179  }
1180 
1181  show_range_stop(s->psession, rl);
1182 
1183  response_close(c, "show");
1184 }
1185 
1186 static void show_records_ready(void *data)
1187 {
1188  struct http_channel *c = (struct http_channel *) data;
1189  struct http_session *s = locate_session(c);
1190  if (s)
1191  {
1193  "show watch released");
1194  show_records(c, s, -1);
1195  }
1196  else {
1197  /* some error message */
1198  }
1199  release_session(c, s);
1200 }
1201 
1202 static void cmd_show(struct http_channel *c)
1203 {
1204  struct http_request *rq = c->request;
1205  struct http_response *rs = c->response;
1206  struct http_session *s = locate_session(c);
1207  const char *block = http_argbyname(rq, "block");
1208  const char *sort = http_argbyname(rq, "sort");
1209  const char *block_error = http_argbyname(rq, "report");
1210  const char *mergekey = http_argbyname(rq, "mergekey");
1211  const char *rank = http_argbyname(rq, "rank");
1212  struct conf_service *service = 0;
1213  struct reclist_sortparms *sp;
1214  int status;
1215  int report_error = 0;
1216 
1217  if (block_error && !strcmp("1", block_error))
1218  report_error = 1;
1219  if (!s)
1220  return;
1221  service = s->psession->service;
1222  if (!sort)
1223  sort = service->default_sort;
1224  if (!(sp = reclist_parse_sortparms(c->nmem, sort, service)))
1225  {
1227  release_session(c, s);
1228  return;
1229  }
1230  session_sort(s->psession, sp, mergekey, rank);
1231 
1232  status = session_active_clients(s->psession);
1233 
1234  if (block && reclist_get_num_records(s->psession->reclist) == 0)
1235  {
1236  if (!strcmp(block, "preferred")
1239  {
1240  // if there is already a watch/block. we do not block this one
1242  show_records_ready, c, c) == 0)
1243  {
1245  "Blocking on command show (preferred targets)");
1246  release_session(c, s);
1247  return;
1248  }
1249  else
1250  {
1251  session_log(s->psession, YLOG_WARN, "Attempt to block"
1252  " multiple times on show (preferred targets) block."
1253  " Not supported!");
1254  if (report_error)
1255  {
1257  "show (preferred targets)");
1258  release_session(c, s);
1259  return;
1260  }
1261  else
1262  session_log(s->psession, YLOG_WARN,
1263  "Ignoring show(preferred) block."
1264  " Returning current result");
1265  }
1266 
1267  }
1268  else if (status)
1269  {
1270  // if there is already a watch/block. we do not block this one
1272  show_records_ready, c, c) != 0)
1273  {
1274  session_log(s->psession, YLOG_WARN, "Attempt to block"
1275  " multiple times on show block. Not supported!");
1276  if (report_error)
1277  {
1278  error(rs, PAZPAR2_ALREADY_BLOCKED, "show");
1279  release_session(c, s);
1280  return;
1281  }
1282  else
1283  session_log(s->psession, YLOG_WARN, "Ignoring show block."
1284  " Returning current result");
1285  }
1286  else
1287  {
1289  "Blocking on command show");
1290  release_session(c, s);
1291  return;
1292  }
1293  }
1294  }
1295  show_records(c, s, status);
1296  release_session(c, s);
1297 }
1298 
1299 static void cmd_ping(struct http_channel *c)
1300 {
1301  struct http_session *s = locate_session(c);
1302  if (!s)
1303  return;
1304  response_open_ok(c, "ping");
1305  response_close(c, "ping");
1306  release_session(c, s);
1307 }
1308 
1309 static void cmd_search(struct http_channel *c)
1310 {
1311  struct http_request *rq = c->request;
1312  struct http_response *rs = c->response;
1313  struct http_session *s = locate_session(c);
1314  const char *query = http_argbyname(rq, "query");
1315  const char *filter = http_argbyname(rq, "filter");
1316  const char *maxrecs = http_argbyname(rq, "maxrecs");
1317  const char *startrecs = http_argbyname(rq, "startrecs");
1318  const char *limit = http_argbyname(rq, "limit");
1319  const char *sort = http_argbyname(rq, "sort");
1320  const char *mergekey = http_argbyname(rq, "mergekey");
1321  const char *rank = http_argbyname(rq, "rank");
1322  enum pazpar2_error_code code;
1323  const char *addinfo = 0;
1324  const char *addinfo2 = 0;
1325  struct reclist_sortparms *sp;
1326  struct conf_service *service = 0;
1327 
1328  if (!s)
1329  return;
1330 
1331  if (!query)
1332  {
1333  error(rs, PAZPAR2_MISSING_PARAMETER, "query");
1334  release_session(c, s);
1335  return;
1336  }
1337  if (!yaz_utf8_check(query))
1338  {
1340  release_session(c, s);
1341  return;
1342  }
1343  service = s->psession->service;
1344  if (!sort)
1345  sort = service->default_sort;
1346 
1347  if (!(sp = reclist_parse_sortparms(c->nmem, sort, s->psession->service)))
1348  {
1350  release_session(c, s);
1351  return;
1352  }
1353 
1354  code = session_search(s->psession, query, startrecs, maxrecs, filter, limit,
1355  &addinfo, &addinfo2, sp, mergekey, rank);
1356  if (code)
1357  {
1358  error2(rs, code, addinfo, addinfo2);
1359  release_session(c, s);
1360  return;
1361  }
1362  response_open_ok(c, "search");
1363  response_close(c, "search");
1364  release_session(c, s);
1365 }
1366 
1367 
1368 static void cmd_stat(struct http_channel *c)
1369 {
1370  struct http_session *s = locate_session(c);
1371  struct statistics stat;
1372  int clients;
1373 
1374  float progress = 0;
1375 
1376  if (!s)
1377  return;
1378 
1379  clients = session_active_clients(s->psession);
1380  statistics(s->psession, &stat);
1381 
1382  if (stat.num_clients > 0)
1383  {
1384  progress = (stat.num_clients - clients) / (float)stat.num_clients;
1385  }
1386 
1387  response_open_command(c, "stat");
1388  wrbuf_printf(c->wrbuf, "\n <activeclients>%d</activeclients>\n", clients);
1389  wrbuf_printf(c->wrbuf, " <hits>" ODR_INT_PRINTF "</hits>\n", stat.num_hits);
1390  wrbuf_printf(c->wrbuf, " <records>%d</records>\n", stat.num_records);
1391  wrbuf_printf(c->wrbuf, " <clients>%d</clients>\n", stat.num_clients);
1392  wrbuf_printf(c->wrbuf, " <unconnected>%d</unconnected>\n", stat.num_no_connection);
1393  wrbuf_printf(c->wrbuf, " <connecting>%d</connecting>\n", stat.num_connecting);
1394  wrbuf_printf(c->wrbuf, " <working>%d</working>\n", stat.num_working);
1395  wrbuf_printf(c->wrbuf, " <idle>%d</idle>\n", stat.num_idle);
1396  wrbuf_printf(c->wrbuf, " <failed>%d</failed>\n", stat.num_failed);
1397  wrbuf_printf(c->wrbuf, " <error>%d</error>\n", stat.num_error);
1398  wrbuf_printf(c->wrbuf, " <progress>%.2f</progress>\n", progress);
1399  response_close(c, "stat");
1400  release_session(c, s);
1401 }
1402 
1403 static void cmd_stop(struct http_channel *c)
1404 {
1405  struct http_session *s = locate_session(c);
1406  if (!s)
1407  return;
1408  response_open_ok(c, "stop");
1409  session_stop(s->psession);
1410  response_close(c, "stop");
1411  release_session(c, s);
1412 }
1413 
1414 static void cmd_info(struct http_channel *c)
1415 {
1416  char yaz_version_str[20];
1417  char yaz_sha1_str[42];
1418 
1419  response_open_command(c, "info");
1420  wrbuf_puts(c->wrbuf, "\n <version>\n");
1421  wrbuf_puts(c->wrbuf, " <pazpar2");
1422 #ifdef PAZPAR2_VERSION_SHA1
1423  wrbuf_printf(c->wrbuf, " sha1=\"%s\"", PAZPAR2_VERSION_SHA1);
1424 #endif
1425  wrbuf_puts(c->wrbuf, ">");
1426  wrbuf_xmlputs(c->wrbuf, VERSION);
1427  wrbuf_puts(c->wrbuf, "</pazpar2>\n");
1428 
1429  yaz_version(yaz_version_str, yaz_sha1_str);
1430  wrbuf_puts(c->wrbuf, " <yaz compiled=\"");
1431  wrbuf_xmlputs(c->wrbuf, YAZ_VERSION);
1432  wrbuf_puts(c->wrbuf, "\" sha1=\"");
1433  wrbuf_xmlputs(c->wrbuf, yaz_sha1_str);
1434  wrbuf_puts(c->wrbuf, "\">");
1435  wrbuf_xmlputs(c->wrbuf, yaz_version_str);
1436  wrbuf_puts(c->wrbuf, "</yaz>\n");
1437 
1438  wrbuf_puts(c->wrbuf, " </version>\n");
1439 #if HAVE_UNISTD_H
1440  {
1441  char hostname_str[64];
1442  if (gethostname(hostname_str, sizeof(hostname_str)) == 0)
1443  {
1444  wrbuf_puts(c->wrbuf, " <host>");
1445  wrbuf_xmlputs(c->wrbuf, hostname_str);
1446  wrbuf_puts(c->wrbuf, "</host>\n");
1447  }
1448  }
1449 #endif
1450  wrbuf_printf(c->wrbuf, " <sessions>%d</sessions>\n", sessions_get_count());
1451  wrbuf_printf(c->wrbuf, " <clients>%d</clients>\n", clients_get_count());
1452  wrbuf_malloc_info(c->wrbuf);
1453  {
1454  char buf[200];
1455  if (nmem_get_status(buf, sizeof(buf) - 1) == 0)
1456  wrbuf_puts(c->wrbuf, buf);
1457  }
1458  info_services(c->server, c->wrbuf);
1459  response_close(c, "info");
1460 }
1461 
1462 struct {
1463  char *name;
1464  void (*fun)(struct http_channel *c);
1465 } commands[] = {
1466  { "init", cmd_init },
1467  { "settings", cmd_settings },
1468  { "stat", cmd_stat },
1469  { "bytarget", cmd_bytarget },
1470  { "show", cmd_show },
1471  { "search", cmd_search },
1472  { "termlist", cmd_termlist },
1473  { "exit", cmd_exit },
1474  { "session-status", cmd_session_status },
1475  { "service", cmd_service },
1476  { "ping", cmd_ping },
1477  { "record", cmd_record },
1478  { "info", cmd_info },
1479  { "stop", cmd_stop },
1480  {0,0}
1481 };
1482 
1484 {
1485  const char *command = http_argbyname(c->request, "command");
1486  struct http_response *rs = http_create_response(c);
1487  int i;
1488 
1489  c->response = rs;
1490 
1491  http_addheader(rs, "Expires", "Thu, 19 Nov 1981 08:52:00 GMT");
1492  http_addheader(rs, "Cache-Control", "no-store, no-cache, must-revalidate, post-check=0, pre-check=0");
1493 
1494  if (!command)
1495  {
1496  error(rs, PAZPAR2_MISSING_PARAMETER, "command");
1497  return;
1498  }
1499  for (i = 0; commands[i].name; i++)
1500  if (!strcmp(commands[i].name, command))
1501  {
1502  (*commands[i].fun)(c);
1503  break;
1504  }
1505  if (!commands[i].name)
1506  error(rs, PAZPAR2_MALFORMED_PARAMETER_VALUE, "command");
1507 
1508  return;
1509 }
1510 
1511 /*
1512  * Local variables:
1513  * c-basic-offset: 4
1514  * c-file-style: "Stroustrup"
1515  * indent-tabs-mode: nil
1516  * End:
1517  * vim: shiftwidth=4 tabstop=8 expandtab
1518  */
1519 
const char * http_argbyname(struct http_request *r, const char *name)
Definition: http.c:292
static void session_status(struct http_channel *c, struct http_session *s)
Definition: http_command.c:636
unsigned checksum
Definition: record.h:73
struct record_metadata * next
Definition: record.h:51
NMEM nmem
Definition: http.h:47
void info_services(struct conf_server *server, WRBUF w)
static void cmd_settings(struct http_channel *c)
Definition: http_command.c:490
#define PAZPAR2_PROTOCOL_VERSION
Definition: http_command.c:46
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
static void cmd_session_status(struct http_channel *c)
Definition: http_command.c:660
#define HTTP_COMMAND_RESPONSE_PREFIX
Definition: http_command.c:48
static void release_session(struct http_channel *c, struct http_session *session)
Definition: http_command.c:363
unsigned int make_sessionid(void)
Definition: http_command.c:304
char * recid
Definition: record.h:96
void iochan_destroy(IOCHAN chan)
Definition: eventl.c:201
#define SESSION_WATCH_SHOW_PREF
Definition: session.h:69
void http_remove_observer(http_channel_observer_t obs)
Definition: http.c:1440
void http_sessions_destroy(http_sessions_t hs)
Definition: http_command.c:108
char code[4]
Definition: http.h:97
struct @2 commands[]
Definition: record.h:60
struct http_session * http_session_create(struct conf_service *service, http_sessions_t http_sessions, unsigned int sesid)
Definition: http_command.c:134
Odr_int num_hits
Definition: session.h:128
http_sessions_t http_sessions_create(void)
Definition: http_command.c:98
static void cmd_stop(struct http_channel *c)
struct http_session * next
Definition: http_command.c:59
int relevance_score
Definition: record.h:92
const char * name
Definition: session.h:134
struct http_session * session_list
Definition: http_command.c:63
int session_set_watch(struct session *s, int what, session_watchfun fun, void *data, struct http_channel *chan)
Definition: session.c:500
iochan_man_t iochan_man
const char * query_type
Definition: session.h:146
struct http_argument * next
Definition: http.h:79
int num_connecting
Definition: session.h:123
static void write_metadata(WRBUF w, struct conf_service *service, struct record_metadata **ml, unsigned flags, int indent)
Definition: http_command.c:831
IOCHAN iochan_create(int fd, IOC_CALLBACK cb, int flags, const char *name)
Definition: eventl.c:209
int num_failed
Definition: session.h:126
char * name
Definition: http.h:77
struct conf_service * service
Definition: session.h:93
struct record_metadata_attr * next
Definition: record.h:45
#define VERSION
Definition: config.h:74
const char * id
Definition: session.h:133
static void show_raw_record_ok(void *data, const char *buf, size_t sz)
Definition: http_command.c:917
int reclist_get_num_records(struct reclist *l)
Definition: reclists.c:400
void statistics(struct session *se, struct statistics *stat)
Definition: session.c:1548
char * content_buf
Definition: http.h:89
pazpar2_error_code
Definition: session.h:36
static const char * get_msg(enum pazpar2_error_code code)
Definition: http_command.c:208
int clients_get_count(void)
Definition: client.c:93
static void cmd_bytarget(struct http_channel *c)
Definition: http_command.c:778
int records
Definition: session.h:140
struct record * next
Definition: record.h:67
http_sessions_t http_sessions
Definition: http.h:57
void show_raw_reset(void *data, struct http_channel *c, void *data2)
Definition: http_command.c:947
void(* fun)(struct http_channel *c)
static void bytarget_result_ready(void *data)
Definition: http_command.c:760
int get_version(struct http_request *rq)
Definition: http_command.c:73
struct http_header * headers
Definition: http.h:91
struct http_argument * arguments
Definition: http.h:92
struct conf_metadata * metadata
static void response_open_ok(struct http_channel *c, const char *command)
Definition: http_command.c:288
int max
Definition: record.h:36
#define PAZPAR2_VERSION_SHA1
Definition: config.h:68
static void cmd_info(struct http_channel *c)
char * value
Definition: http.h:78
void http_addheader(struct http_response *r, const char *name, const char *value)
Definition: http.c:282
static void bytarget_response(struct http_channel *c, struct http_session *s, const char *cmd_status)
Definition: http_command.c:672
WRBUF wrbuf
Definition: http.h:48
struct conf_server * server
#define PZ_NAME
Definition: settings.h:33
static void cmd_ping(struct http_channel *c)
WRBUF relevance_explain1
Definition: record.h:98
static void show_records_ready(void *data)
char * name
struct conf_service * locate_service(struct conf_server *server, const char *service_id)
struct http_request * request
Definition: http.h:50
struct data_types::@3 text
IOCHAN timeout_iochan
Definition: http_command.c:51
struct http_channel * channel
Definition: http.h:99
void http_command(struct http_channel *c)
static void response_close(struct http_channel *c, const char *command)
Definition: http_command.c:294
void perform_termlist(struct http_channel *c, struct session *se, const char *name, int num, int version)
Definition: session.c:1259
int predictable_sessions
Definition: parameters.h:29
const char * http_lookup_header(struct http_header *header, const char *name)
Definition: http.c:119
static void show_raw_record_ok_binary(void *data, const char *buf, size_t sz)
Definition: http_command.c:931
static void cmd_search(struct http_channel *c)
static void show_records(struct http_channel *c, struct http_session *s, int active)
int num_working
Definition: session.h:124
int num_error
Definition: session.h:127
const char * session_setting_oneval(struct session_database *db, int offset)
Definition: session.c:433
static void apply_local_setting(void *client_data, struct setting *set)
Definition: http_command.c:482
int num_clients
Definition: session.h:121
static void cmd_show(struct http_channel *c)
struct data_types::@4 number
int iochan_add(iochan_man_t man, IOCHAN chan, int slack)
Definition: eventl.c:173
static void cmd_stat(struct http_channel *c)
size_t session_get_memory_status(struct session *session)
Definition: session.c:1082
static void response_open_command(struct http_channel *c, const char *command)
Definition: http_command.c:280
unsigned int session_id
Definition: http_command.c:53
int position
Definition: record.h:69
#define iochan_setdata(i, d)
Definition: eventl.h:63
void http_send_response(struct http_channel *ch)
Definition: http.c:844
struct reclist * reclist
Definition: session.h:101
static YAZ_MUTEX g_http_session_mutex
Definition: http_command.c:68
void session_init_databases(struct session *se)
Definition: session.c:987
struct record_metadata ** metadata
Definition: record.h:63
#define SESSION_WATCH_RECORD
Definition: session.h:68
#define SESSION_WATCH_BYTARGET
Definition: session.h:71
static int process_settings(struct session *se, struct http_request *rq, struct http_response *rs)
Definition: http_command.c:375
union data_types data
Definition: record.h:49
void session_stop(struct session *se)
Definition: session.c:791
static void termlist_result_ready(void *data)
Definition: http_command.c:558
int activity_counter
Definition: http_command.c:56
int sessions_get_count(void)
Definition: session.c:116
http_channel_observer_t http_add_observer(struct http_channel *c, void *data, http_channel_destroy_t des)
Definition: http.c:1427
void http_close_server(struct conf_server *server)
Definition: http.c:1359
const char * message
Definition: session.h:138
enum conf_metadata_type type
static void show_record(struct http_channel *c, struct http_session *s)
Definition: http_command.c:955
int num_idle
Definition: session.h:125
struct parameters global_parameters
Definition: session.c:86
void show_single_stop(struct session *se, struct record_cluster *rec)
Definition: session.c:1378
void session_apply_setting(struct session *se, const char *dbname, const char *name, const char *value)
Definition: session.c:1018
static void cmd_exit(struct http_channel *c)
Definition: http_command.c:405
static int g_http_sessions
Definition: http_command.c:69
int num_records
Definition: session.h:129
Odr_int approximation
Definition: session.h:136
struct record_metadata ** metadata
Definition: record.h:87
struct session * psession
Definition: http_command.c:52
char * suggestions_xml
Definition: session.h:145
#define iochan_activity(i)
Definition: eventl.h:69
const char * disp
Definition: record.h:29
void session_sort(struct session *se, struct reclist_sortparms *sp, const char *mergekey, const char *rank)
Definition: session.c:685
char * payload
Definition: http.h:101
void session_destroy(struct session *se)
Definition: session.c:1053
int debug_mode
Definition: parameters.h:28
char * settings_xml
Definition: session.h:144
static void cmd_service(struct http_channel *c)
Definition: http_command.c:647
Odr_int hits
Definition: session.h:135
YAZ_MUTEX mutex
Definition: http_command.c:64
static void error(struct http_response *rs, enum pazpar2_error_code code, const char *addinfo)
Definition: http_command.c:273
static void show_raw_record_error(void *data, const char *addinfo)
Definition: http_command.c:906
struct reclist_sortparms * reclist_parse_sortparms(NMEM nmem, const char *parms, struct conf_service *service)
Definition: reclists.c:71
void show_range_stop(struct session *se, struct record_cluster **recs)
Definition: session.c:1543
#define iochan_getdata(i)
Definition: eventl.h:62
char * server_id
char * content_type
Definition: http.h:102
const char * client_get_id(struct client *cl)
Definition: client.c:1833
char * msg
Definition: http.h:98
struct conf_service * service_create(struct conf_server *server, xmlNode *node)
static void cmd_termlist(struct http_channel *c)
Definition: http_command.c:576
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 cmd_record_ready(void *data)
int min
Definition: record.h:35
static void cmd_record(struct http_channel *c)
static struct http_session * locate_session(struct http_channel *c)
Definition: http_command.c:333
Definition: eventl.h:31
struct client * client
Definition: record.h:61
const char * query_data
Definition: session.h:147
struct session * session_create(NMEM nmem, struct conf_service *service, unsigned session_id)
Definition: session.c:1093
struct record_metadata_attr * attributes
Definition: record.h:52
void pazpar2_mutex_create(YAZ_MUTEX *p, const char *name)
Definition: ppmutex.c:39
struct http_response * response
Definition: http.h:51
void session_log(struct session *s, int level, const char *fmt,...)
Definition: session.c:2509
struct hitsbytarget * get_hitsbytarget(struct session *se, int *count, NMEM nmem)
Definition: session.c:1184
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
void http_session_destroy(struct http_session *s)
Definition: http_command.c:169
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
static void termlist_response(struct http_channel *c, struct http_session *s, const char *cmd_status)
Definition: http_command.c:532
static void session_timeout(IOCHAN i, int event)
Definition: http_command.c:128
struct http_channel * http_channel_observer_chan(http_channel_observer_t obs)
Definition: http.c:1452
Z39.50 client.
int session_active_clients(struct session *s)
Definition: session.c:637
struct record * records
Definition: record.h:100
#define SESSION_WATCH_TERMLIST
Definition: session.h:70
int settings_read_node_x(xmlNode *n, void *client_data, void(*fun)(void *client_data, struct setting *set))
Definition: settings.c:174
int num_no_connection
Definition: session.h:122
static void cmd_init(struct http_channel *c)
Definition: http_command.c:415
#define iochan_settimeout(i, t)
Definition: eventl.h:68
#define SESSION_WATCH_SHOW
Definition: session.h:67
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
int session_is_preferred_clients_ready(struct session *s)
Definition: session.c:649
struct http_response * http_create_response(struct http_channel *c)
Definition: http.c:311
int destroy_counter
Definition: http_command.c:55
int diagnostic
Definition: session.h:137
const char * addinfo
Definition: session.h:139
struct session_database * client_get_database(struct client *cl)
Definition: client.c:251
static void write_subrecord(struct record *r, WRBUF w, struct conf_service *service, unsigned flags, int indent)
Definition: http_command.c:883
int filtered
Definition: session.h:141
struct conf_server * server
Definition: http.h:55
const char * snippet
Definition: record.h:32
const char * state
Definition: session.h:142
http_sessions_t http_sessions
Definition: http_command.c:58
char * default_sort
int http_session_use(int delta)
Definition: http_command.c:83
double fnumber
Definition: record.h:38
control MUTEX debugging
WRBUF relevance_explain2
Definition: record.h:99
int content_len
Definition: http.h:90