32 typedef int socklen_t;
36 #include <sys/socket.h>
39 #include <sys/types.h>
41 #include <yaz/snprintf.h>
58 #include <yaz/yaz-util.h>
59 #include <yaz/comstack.h>
61 #include <yaz/mutex.h>
68 #define MAX_HTTP_HEADER 4096
71 #define strncasecmp _strnicmp
72 #define strcasecmp _stricmp
77 #define HTTP_BUF_SIZE 4096
94 #define CLOSESOCKET(x) closesocket(x)
96 #define CLOSESOCKET(x) close(x)
121 for (; header; header = header->
next)
122 if (!strcasecmp(name, header->
name))
123 return header->
value;
129 struct http_buf *r = xmalloc(
sizeof(*r));
163 memcpy((*p)->buf, b, tocopy);
176 queue = &(*queue)->
next;
191 while (b && rd < len)
193 int toread = len - rd;
196 memcpy(buf + rd, b->
buf + b->
offset, toread);
206 for (; b; b = b->
next)
216 while ((*b) && rd < len)
218 int toread = len - rd;
219 if (toread > (*b)->len)
221 memcpy(buf + rd, (*b)->buf + (*b)->offset, toread);
223 if (toread < (*b)->len)
226 (*b)->offset += toread;
250 else if (*i ==
'%' && i[1] && i[2])
254 sscanf(i,
"%2x", &v);
269 if (strchr(
" /:", *i))
271 sprintf(o,
"%%%.2X", (
int) *i);
285 h->
name = nmem_strdup(c->
nmem, name);
297 if (!strcmp(p->
name, name))
304 for (; h; h = h->
next)
305 if (!strcmp(h->
name, name))
313 strcpy(r->
code,
"200");
323 static const char *
next_crlf(
const char *cp,
size_t *skipped)
325 const char *next_cp = strchr(cp,
'\n');
328 if (next_cp > cp && next_cp[-1] ==
'\r')
329 *skipped = next_cp - cp - 1;
331 *skipped = next_cp - cp;
346 const char *b =
next_crlf(buf, &skipped);
359 if (len + content_len <= sz)
360 return len + content_len;
365 if (!strncasecmp(buf,
"Content-Length:", 15))
367 const char *cp = buf+15;
371 while (*cp && isdigit(*(
const unsigned char *)cp))
372 content_len = content_len*10 + (*cp++ -
'0');
400 memcpy(tmp, buf, len);
401 for (p = tmp; *p && *p !=
' '; p++)
405 for (p2 = p; *p2 && *p2 !=
' ' && p2 - p < 3; p2++)
406 r->
code[p2 - p] = *p2;
407 if (!(p = strstr(tmp,
"\r\n")))
412 if (!(p2 = strstr(p,
"\r\n")))
419 char *
value = strchr(p,
':');
424 while (isspace(*(
const unsigned char *) value))
445 const char *p2 = args;
450 const char *equal = strchr(p2,
'=');
451 const char *eoa = strchr(p2,
'&');
454 yaz_log(YLOG_WARN,
"Expected '=' in argument");
458 eoa = equal + strlen(equal);
459 else if (equal > eoa)
461 yaz_log(YLOG_WARN,
"Missing '&' in argument");
465 a->
name = nmem_strdupn(nmem, p2, equal - p2);
466 a->
value = nmem_strdupn(nmem, equal+1, eoa - equal - 1);
484 char *start = nmem_malloc(c->
nmem, len+1);
489 yaz_log(YLOG_WARN,
"http_buf_read < len (%d)", len);
499 for (p = buf, p2 = r->
method; *p && *p !=
' ' && p - buf < 19; p++)
503 yaz_log(YLOG_WARN,
"Unexpected HTTP method in request");
508 if (!(buf = strchr(buf,
' ')))
510 yaz_log(YLOG_WARN,
"Missing Request-URI in HTTP request");
514 if (!(p = strchr(buf,
' ')))
516 yaz_log(YLOG_WARN,
"HTTP Request-URI not terminated (too long?)");
520 if ((p2 = strchr(buf,
'?')))
522 r->
path = nmem_strdup(c->
nmem, buf);
531 if (strncmp(buf,
"HTTP/", 5))
539 if (!p || skipped < 3 || skipped > 5)
558 else if (skipped == 0)
566 char *n_v = nmem_malloc(c->
nmem, skipped+1);
569 memcpy(n_v, buf, skipped);
572 if (!(cp = strchr(n_v,
':')))
574 h->
name = nmem_strdupn(c->
nmem, n_v, cp - n_v);
586 if (!strcmp(c->
version,
"1.0"))
589 if (v && !strcmp(v,
"Keep-Alive"))
597 if (v && !strcmp(v,
"close"))
602 if (buf < start + len)
609 if (!yaz_strcmp_del(
"application/x-www-form-urlencoded",
623 wrbuf_rewind(c->
wrbuf);
630 wrbuf_printf(c->
wrbuf,
"Content-Length: %d\r\n", r->
payload ?
642 yaz_log(YLOG_WARN,
"Sending non-wellformed "
643 "response (bug #1162");
644 yaz_log(YLOG_WARN,
"payload: %s", r->
payload);
648 wrbuf_puts(c->
wrbuf,
"\r\n");
655 FILE *lf = yaz_log_file();
656 yaz_log(YLOG_LOG,
"Response:");
657 fwrite(wrbuf_buf(c->
wrbuf), 1, wrbuf_len(c->
wrbuf), lf);
668 wrbuf_rewind(c->
wrbuf);
677 wrbuf_puts(c->
wrbuf,
"\r\n");
683 yaz_log(YLOG_LOG,
"WRITING TO PROXY:\n%s\n----",
684 wrbuf_cstr(c->
wrbuf));
709 while (hp && hp->
next)
712 if(name && strlen(name)&& value && strlen(value)){
713 hpnew = nmem_malloc(ch->
nmem,
sizeof *hpnew);
714 hpnew->
name = nmem_strdup(ch->
nmem, name);
715 hpnew->
value = nmem_strdup(ch->
nmem, value);
731 if (WSAGetLastError() == WSAEWOULDBLOCK)
734 if (errno == EINPROGRESS)
744 flags = (flags & CS_FLAGS_BLOCKING) ? 0 : 1;
745 if (ioctlsocket(sock, FIONBIO, &flags) < 0)
746 yaz_log(YLOG_FATAL|YLOG_ERRNO,
"ioctlsocket");
748 if ((flags = fcntl(sock, F_GETFL, 0)) < 0)
749 yaz_log(YLOG_FATAL|YLOG_ERRNO,
"fcntl");
750 if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) < 0)
751 yaz_log(YLOG_FATAL|YLOG_ERRNO,
"fcntl2");
761 char server_port[16] =
"";
770 if (!(pe = getprotobyname(
"tcp"))) {
773 if ((sock = socket(PF_INET, SOCK_STREAM, pe->p_proto)) < 0)
775 yaz_log(YLOG_WARN|YLOG_ERRNO,
"socket");
778 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (
char*)
779 &one,
sizeof(one)) < 0)
782 if (connect(sock, (
struct sockaddr *)
788 yaz_log(YLOG_WARN|YLOG_ERRNO,
"Proxy connect");
808 yaz_log(YLOG_WARN,
"Failed to find Host header in proxy");
814 char server_via[128];
820 "X-Pazpar2-Server-Host", ser->
host);
821 sprintf(server_port,
"%d", ser->
port);
823 "X-Pazpar2-Server-Port", server_port);
824 yaz_snprintf(server_via,
sizeof(server_via),
848 yaz_log(YLOG_WARN,
"Failed to serialize HTTP response");
855 ch->
state = Http_Idle;
866 sprintf(rs->
code,
"%d", no);
868 rs->
msg = nmem_strdup(hc->
nmem, msg);
870 yaz_snprintf(rs->
payload, 99,
"<error>HTTP Error %d: %s</error>\n",
887 if (res == -1 && errno == EAGAIN)
898 gettimeofday(&tv, 0);
900 (
long long) tv.tv_sec, (
long long) tv.tv_usec,
909 htbuf->
buf[res] =
'\0';
915 if (hc->
state == Http_Busy)
921 nmem_reset(hc->
nmem);
930 gettimeofday(&tv, 0);
932 (
long long) tv.tv_sec, (
long long) tv.tv_usec,
941 yaz_log(YLOG_WARN,
"Failed to parse request");
957 hc->
state = Http_Busy;
973 yaz_log(YLOG_WARN|YLOG_ERRNO,
"write");
984 gettimeofday(&tv, 0);
986 (
long long) tv.tv_sec, (
long long) tv.tv_usec,
1022 yaz_log(YLOG_WARN,
"Unexpected event on connection");
1047 yaz_log(YLOG_WARN,
"Proxy read came up short");
1062 htbuf->
buf[res] =
'\0';
1072 if (!(htbuf = pc->
oqueue))
1080 yaz_log(YLOG_WARN|YLOG_ERRNO,
"write");
1084 if (res == htbuf->
len)
1101 yaz_log(YLOG_WARN,
"Unexpected event on connection");
1138 nmem_destroy(s->
nmem);
1139 wrbuf_destroy(s->
wrbuf);
1150 r->
nmem = nmem_create();
1151 r->
wrbuf = wrbuf_alloc();
1168 yaz_log(YLOG_WARN,
"Invalid HTTP forward address");
1171 strcpy(r->
addr, addr);
1181 struct sockaddr addr;
1190 if ((s = accept(fd, &addr, &len)) < 0)
1192 yaz_log(YLOG_WARN|YLOG_ERRNO,
"accept");
1195 if (getnameinfo(&addr, len, host,
sizeof(host)-1, 0, 0, NI_NUMERICHOST))
1197 yaz_log(YLOG_WARN|YLOG_ERRNO,
"getnameinfo");
1203 yaz_log(YLOG_DEBUG,
"New command connection");
1205 "http_session_socket");
1216 const char *record_fname)
1222 FILE *record_file = 0;
1223 struct addrinfo hints, *ai = 0;
1227 yaz_log(YLOG_LOG,
"HTTP listener %s", addr);
1230 hints.ai_family = AF_UNSPEC;
1231 hints.ai_socktype = SOCK_STREAM;
1232 hints.ai_protocol = 0;
1233 hints.ai_addrlen = 0;
1234 hints.ai_addr = NULL;
1235 hints.ai_canonname = NULL;
1236 hints.ai_next = NULL;
1238 pp = strchr(addr,
':');
1241 WRBUF w = wrbuf_alloc();
1242 wrbuf_write(w, addr, pp - addr);
1243 if (!strcmp(wrbuf_cstr(w),
"@"))
1246 hints.ai_flags = AI_PASSIVE;
1247 hints.ai_family = AF_INET6;
1248 error = getaddrinfo(0, pp + 1, &hints, &ai);
1251 error = getaddrinfo(wrbuf_cstr(w), pp + 1, &hints, &ai);
1257 hints.ai_flags = AI_PASSIVE;
1258 hints.ai_family = AF_INET;
1259 error = getaddrinfo(0, addr, &hints, &ai);
1263 yaz_log(YLOG_FATAL,
"Failed to resolve %s: %s", addr,
1264 gai_strerror(error));
1267 l = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
1270 yaz_log(YLOG_FATAL|YLOG_ERRNO,
"socket");
1274 if (ipv6_only >= 0 &&
1275 setsockopt(l, IPPROTO_IPV6, IPV6_V6ONLY, &ipv6_only,
sizeof(ipv6_only)))
1277 yaz_log(YLOG_FATAL|YLOG_ERRNO,
"setsockopt IPV6_V6ONLY %s %d", addr,
1283 if (setsockopt(l, SOL_SOCKET, SO_REUSEADDR, &one,
sizeof(one)))
1285 yaz_log(YLOG_FATAL|YLOG_ERRNO,
"setsockopt SO_REUSEADDR %s", addr);
1290 if (bind(l, ai->ai_addr, ai->ai_addrlen) < 0)
1292 yaz_log(YLOG_FATAL|YLOG_ERRNO,
"bind %s", addr);
1298 if (listen(l, SOMAXCONN) < 0)
1300 yaz_log(YLOG_FATAL|YLOG_ERRNO,
"listen %s", addr);
1307 record_file = fopen(record_fname,
"wb");
1310 yaz_log(YLOG_FATAL|YLOG_ERRNO,
"fopen %s", record_fname);
1345 WRBUF w = wrbuf_alloc();
1347 yaz_log(YLOG_LOG,
"HTTP backend %s", host);
1349 p = strchr(host,
':');
1353 wrbuf_write(w, host, p - host);
1359 wrbuf_puts(w, host);
1361 if (!(he = gethostbyname(wrbuf_cstr(w))))
1363 fprintf(stderr,
"Failed to lookup '%s'\n", wrbuf_cstr(w));
1371 he->h_addr_list[0], he->h_length);
1448 yaz_mutex_enter(hs->
mutex);
1450 yaz_mutex_leave(hs->
mutex);
1456 yaz_mutex_destroy(&hs->
mutex);
1467 yaz_mutex_enter(hs->
mutex);
1469 yaz_mutex_leave(hs->
mutex);