PageRenderTime 46ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/prerequisites/yaz-3.0.52/src/http.c

https://github.com/opendream/hotri
C | 553 lines | 464 code | 51 blank | 38 comment | 131 complexity | 9dab54e95b25d9bb505605a86a8b4e82 MD5 | raw file
Possible License(s): GPL-3.0
  1. /* This file is part of the YAZ toolkit.
  2. * Copyright (C) 1995-2009 Index Data
  3. * See the file LICENSE for details.
  4. */
  5. /**
  6. * \file http.c
  7. * \brief Implements HTTP decoding
  8. */
  9. #include <ctype.h>
  10. #include <yaz/odr.h>
  11. #include <yaz/yaz-version.h>
  12. #include <yaz/yaz-iconv.h>
  13. #include <yaz/matchstr.h>
  14. #include <yaz/zgdu.h>
  15. #ifdef WIN32
  16. #define strncasecmp _strnicmp
  17. #define strcasecmp _stricmp
  18. #endif
  19. /*
  20. * This function's counterpart, yaz_base64decode(), is in srwutil.c.
  21. * I feel bad that they're not together, but each function is only
  22. * needed in one place, and those places are not together. Maybe one
  23. * day we'll move them into a new httputil.c, and declare them in a
  24. * corresponding httputil.h
  25. */
  26. static void yaz_base64encode(const char *in, char *out)
  27. {
  28. static char encoding[] =
  29. "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  30. unsigned char buf[3];
  31. long n;
  32. while (*in != 0) {
  33. char *pad = 0;
  34. buf[0] = in[0];
  35. buf[1] = in[1];
  36. if (in[1] == 0) {
  37. buf[2] = 0;
  38. pad = "==";
  39. } else {
  40. buf[2] = in[2];
  41. if (in[2] == 0)
  42. pad = "=";
  43. }
  44. /* Treat three eight-bit numbers as on 24-bit number */
  45. n = (buf[0] << 16) + (buf[1] << 8) + buf[2];
  46. /* Write the six-bit chunks out as four encoded characters */
  47. *out++ = encoding[(n >> 18) & 63];
  48. *out++ = encoding[(n >> 12) & 63];
  49. if (in[1] != 0)
  50. *out++ = encoding[(n >> 6) & 63];
  51. if (in[1] != 0 && in[2] != 0)
  52. *out++ = encoding[n & 63];
  53. if (pad != 0) {
  54. while (*pad != 0)
  55. *out++ = *pad++;
  56. break;
  57. }
  58. in += 3;
  59. }
  60. *out++ = 0;
  61. }
  62. static int decode_headers_content(ODR o, int off, Z_HTTP_Header **headers,
  63. char **content_buf, int *content_len)
  64. {
  65. int i = off;
  66. int chunked = 0;
  67. *headers = 0;
  68. while (i < o->size-1 && o->buf[i] == '\n')
  69. {
  70. int po;
  71. i++;
  72. if (o->buf[i] == '\r' && i < o->size-1 && o->buf[i+1] == '\n')
  73. {
  74. i++;
  75. break;
  76. }
  77. if (o->buf[i] == '\n')
  78. break;
  79. for (po = i; ; i++)
  80. {
  81. if (i == o->size)
  82. {
  83. o->error = OHTTP;
  84. return 0;
  85. }
  86. else if (o->buf[i] == ':')
  87. break;
  88. }
  89. *headers = (Z_HTTP_Header *) odr_malloc(o, sizeof(**headers));
  90. (*headers)->name = (char*) odr_malloc(o, i - po + 1);
  91. memcpy ((*headers)->name, o->buf + po, i - po);
  92. (*headers)->name[i - po] = '\0';
  93. i++;
  94. while (i < o->size-1 && o->buf[i] == ' ')
  95. i++;
  96. for (po = i; i < o->size-1 && !strchr("\r\n", o->buf[i]); i++)
  97. ;
  98. (*headers)->value = (char*) odr_malloc(o, i - po + 1);
  99. memcpy ((*headers)->value, o->buf + po, i - po);
  100. (*headers)->value[i - po] = '\0';
  101. if (!strcasecmp((*headers)->name, "Transfer-Encoding")
  102. &&
  103. !strcasecmp((*headers)->value, "chunked"))
  104. chunked = 1;
  105. headers = &(*headers)->next;
  106. if (i < o->size-1 && o->buf[i] == '\r')
  107. i++;
  108. }
  109. *headers = 0;
  110. if (o->buf[i] != '\n')
  111. {
  112. o->error = OHTTP;
  113. return 0;
  114. }
  115. i++;
  116. if (chunked)
  117. {
  118. int off = 0;
  119. /* we know buffer will be smaller than o->size - i*/
  120. *content_buf = (char*) odr_malloc(o, o->size - i);
  121. while (1)
  122. {
  123. /* chunk length .. */
  124. int chunk_len = 0;
  125. for (; i < o->size-2; i++)
  126. if (isdigit(o->buf[i]))
  127. chunk_len = chunk_len * 16 +
  128. (o->buf[i] - '0');
  129. else if (isupper(o->buf[i]))
  130. chunk_len = chunk_len * 16 +
  131. (o->buf[i] - ('A'-10));
  132. else if (islower(o->buf[i]))
  133. chunk_len = chunk_len * 16 +
  134. (o->buf[i] - ('a'-10));
  135. else
  136. break;
  137. /* chunk extension ... */
  138. while (o->buf[i] != '\r' && o->buf[i+1] != '\n')
  139. {
  140. if (i >= o->size-2)
  141. {
  142. o->error = OHTTP;
  143. return 0;
  144. }
  145. i++;
  146. }
  147. i += 2; /* skip CRLF */
  148. if (chunk_len == 0)
  149. break;
  150. if (chunk_len < 0 || off + chunk_len > o->size)
  151. {
  152. o->error = OHTTP;
  153. return 0;
  154. }
  155. /* copy chunk .. */
  156. memcpy (*content_buf + off, o->buf + i, chunk_len);
  157. i += chunk_len + 2; /* skip chunk+CRLF */
  158. off += chunk_len;
  159. }
  160. if (!off)
  161. *content_buf = 0;
  162. *content_len = off;
  163. }
  164. else
  165. {
  166. if (i > o->size)
  167. {
  168. o->error = OHTTP;
  169. return 0;
  170. }
  171. else if (i == o->size)
  172. {
  173. *content_buf = 0;
  174. *content_len = 0;
  175. }
  176. else
  177. {
  178. *content_len = o->size - i;
  179. *content_buf = (char*) odr_malloc(o, *content_len + 1);
  180. memcpy(*content_buf, o->buf + i, *content_len);
  181. (*content_buf)[*content_len] = '\0';
  182. }
  183. }
  184. return 1;
  185. }
  186. void z_HTTP_header_add_content_type(ODR o, Z_HTTP_Header **hp,
  187. const char *content_type,
  188. const char *charset)
  189. {
  190. const char *l = "Content-Type";
  191. if (charset)
  192. {
  193. char *ctype = (char *)
  194. odr_malloc(o, strlen(content_type)+strlen(charset) + 15);
  195. sprintf(ctype, "%s; charset=%s", content_type, charset);
  196. z_HTTP_header_add(o, hp, l, ctype);
  197. }
  198. else
  199. z_HTTP_header_add(o, hp, l, content_type);
  200. }
  201. /*
  202. * HTTP Basic authentication is described at:
  203. * http://tools.ietf.org/html/rfc1945#section-11.1
  204. */
  205. void z_HTTP_header_add_basic_auth(ODR o, Z_HTTP_Header **hp,
  206. const char *username, const char *password)
  207. {
  208. char *tmp, *buf;
  209. int len;
  210. if (username == 0)
  211. return;
  212. len = strlen(username) + strlen(password);
  213. tmp = (char *) odr_malloc(o, len+2);
  214. sprintf(tmp, "%s:%s", username, password);
  215. buf = (char *) odr_malloc(o, (len+1) * 8/6 + 12);
  216. strcpy(buf, "Basic ");
  217. yaz_base64encode(tmp, &buf[strlen(buf)]);
  218. z_HTTP_header_add(o, hp, "Authorization", buf);
  219. }
  220. void z_HTTP_header_add(ODR o, Z_HTTP_Header **hp, const char *n,
  221. const char *v)
  222. {
  223. while (*hp)
  224. hp = &(*hp)->next;
  225. *hp = (Z_HTTP_Header *) odr_malloc(o, sizeof(**hp));
  226. (*hp)->name = odr_strdup(o, n);
  227. (*hp)->value = odr_strdup(o, v);
  228. (*hp)->next = 0;
  229. }
  230. const char *z_HTTP_header_lookup(const Z_HTTP_Header *hp, const char *n)
  231. {
  232. for (; hp; hp = hp->next)
  233. if (!yaz_matchstr(hp->name, n))
  234. return hp->value;
  235. return 0;
  236. }
  237. Z_GDU *z_get_HTTP_Request(ODR o)
  238. {
  239. Z_GDU *p = (Z_GDU *) odr_malloc(o, sizeof(*p));
  240. Z_HTTP_Request *hreq;
  241. p->which = Z_GDU_HTTP_Request;
  242. p->u.HTTP_Request = (Z_HTTP_Request *) odr_malloc(o, sizeof(*hreq));
  243. hreq = p->u.HTTP_Request;
  244. hreq->headers = 0;
  245. hreq->content_len = 0;
  246. hreq->content_buf = 0;
  247. hreq->version = "1.1";
  248. hreq->method = "POST";
  249. hreq->path = "/";
  250. z_HTTP_header_add(o, &hreq->headers, "User-Agent", "YAZ/" YAZ_VERSION);
  251. return p;
  252. }
  253. Z_GDU *z_get_HTTP_Request_host_path(ODR odr,
  254. const char *host,
  255. const char *path)
  256. {
  257. Z_GDU *p = z_get_HTTP_Request(odr);
  258. p->u.HTTP_Request->path = odr_strdup(odr, path);
  259. if (host)
  260. {
  261. const char *cp0 = strstr(host, "://");
  262. const char *cp1 = 0;
  263. if (cp0)
  264. cp0 = cp0+3;
  265. else
  266. cp0 = host;
  267. cp1 = strchr(cp0, '/');
  268. if (!cp1)
  269. cp1 = cp0+strlen(cp0);
  270. if (cp0 && cp1)
  271. {
  272. char *h = (char*) odr_malloc(odr, cp1 - cp0 + 1);
  273. memcpy (h, cp0, cp1 - cp0);
  274. h[cp1-cp0] = '\0';
  275. z_HTTP_header_add(odr, &p->u.HTTP_Request->headers,
  276. "Host", h);
  277. }
  278. }
  279. return p;
  280. }
  281. Z_GDU *z_get_HTTP_Response(ODR o, int code)
  282. {
  283. Z_GDU *p = (Z_GDU *) odr_malloc(o, sizeof(*p));
  284. Z_HTTP_Response *hres;
  285. p->which = Z_GDU_HTTP_Response;
  286. p->u.HTTP_Response = (Z_HTTP_Response *) odr_malloc(o, sizeof(*hres));
  287. hres = p->u.HTTP_Response;
  288. hres->headers = 0;
  289. hres->content_len = 0;
  290. hres->content_buf = 0;
  291. hres->code = code;
  292. hres->version = "1.1";
  293. z_HTTP_header_add(o, &hres->headers, "Server",
  294. "YAZ/" YAZ_VERSION);
  295. if (code != 200)
  296. {
  297. hres->content_buf = (char*) odr_malloc(o, 400);
  298. sprintf(hres->content_buf,
  299. "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\""
  300. " \"http://www.w3.org/TR/html4/strict.dtd\">\n"
  301. "<HTML>\n"
  302. " <HEAD>\n"
  303. " <TITLE>YAZ " YAZ_VERSION "</TITLE>\n"
  304. " </HEAD>\n"
  305. " <BODY>\n"
  306. " <P><A HREF=\"http://www.indexdata.com/yaz/\">YAZ</A> "
  307. YAZ_VERSION "</P>\n"
  308. " <P>Error: %d</P>\n"
  309. " <P>Description: %.50s</P>\n"
  310. " </BODY>\n"
  311. "</HTML>\n",
  312. code, z_HTTP_errmsg(code));
  313. hres->content_len = strlen(hres->content_buf);
  314. z_HTTP_header_add(o, &hres->headers, "Content-Type", "text/html");
  315. }
  316. return p;
  317. }
  318. const char *z_HTTP_errmsg(int code)
  319. {
  320. if (code == 200)
  321. return "OK";
  322. else if (code == 400)
  323. return "Bad Request";
  324. else if (code == 404)
  325. return "Not Found";
  326. else if (code == 405)
  327. return "Method Not Allowed";
  328. else if (code == 500)
  329. return "Internal Error";
  330. else
  331. return "Unknown Error";
  332. }
  333. int yaz_decode_http_response(ODR o, Z_HTTP_Response **hr_p)
  334. {
  335. int i, po;
  336. Z_HTTP_Response *hr = (Z_HTTP_Response *) odr_malloc(o, sizeof(*hr));
  337. *hr_p = hr;
  338. hr->content_buf = 0;
  339. hr->content_len = 0;
  340. po = i = 5;
  341. while (i < o->size-2 && !strchr(" \r\n", o->buf[i]))
  342. i++;
  343. hr->version = (char *) odr_malloc(o, i - po + 1);
  344. if (i - po)
  345. memcpy(hr->version, o->buf + po, i - po);
  346. hr->version[i-po] = 0;
  347. if (o->buf[i] != ' ')
  348. {
  349. o->error = OHTTP;
  350. return 0;
  351. }
  352. i++;
  353. hr->code = 0;
  354. while (i < o->size-2 && o->buf[i] >= '0' && o->buf[i] <= '9')
  355. {
  356. hr->code = hr->code*10 + (o->buf[i] - '0');
  357. i++;
  358. }
  359. while (i < o->size-1 && o->buf[i] != '\n')
  360. i++;
  361. return decode_headers_content(o, i, &hr->headers,
  362. &hr->content_buf, &hr->content_len);
  363. }
  364. int yaz_decode_http_request(ODR o, Z_HTTP_Request **hr_p)
  365. {
  366. int i, po;
  367. Z_HTTP_Request *hr = (Z_HTTP_Request *) odr_malloc(o, sizeof(*hr));
  368. *hr_p = hr;
  369. /* method .. */
  370. for (i = 0; o->buf[i] != ' '; i++)
  371. if (i >= o->size-5 || i > 30)
  372. {
  373. o->error = OHTTP;
  374. return 0;
  375. }
  376. hr->method = (char *) odr_malloc(o, i+1);
  377. memcpy (hr->method, o->buf, i);
  378. hr->method[i] = '\0';
  379. /* path */
  380. po = i+1;
  381. for (i = po; o->buf[i] != ' '; i++)
  382. if (i >= o->size-5)
  383. {
  384. o->error = OHTTP;
  385. return 0;
  386. }
  387. hr->path = (char *) odr_malloc(o, i - po + 1);
  388. memcpy (hr->path, o->buf+po, i - po);
  389. hr->path[i - po] = '\0';
  390. /* HTTP version */
  391. i++;
  392. if (i > o->size-5 || memcmp(o->buf+i, "HTTP/", 5))
  393. {
  394. o->error = OHTTP;
  395. return 0;
  396. }
  397. i+= 5;
  398. po = i;
  399. while (i < o->size && !strchr("\r\n", o->buf[i]))
  400. i++;
  401. hr->version = (char *) odr_malloc(o, i - po + 1);
  402. memcpy(hr->version, o->buf + po, i - po);
  403. hr->version[i - po] = '\0';
  404. /* headers */
  405. if (i < o->size-1 && o->buf[i] == '\r')
  406. i++;
  407. if (o->buf[i] != '\n')
  408. {
  409. o->error = OHTTP;
  410. return 0;
  411. }
  412. return decode_headers_content(o, i, &hr->headers,
  413. &hr->content_buf, &hr->content_len);
  414. }
  415. int yaz_encode_http_response(ODR o, Z_HTTP_Response *hr)
  416. {
  417. char sbuf[80];
  418. Z_HTTP_Header *h;
  419. int top0 = o->top;
  420. sprintf(sbuf, "HTTP/%s %d %s\r\n", hr->version,
  421. hr->code,
  422. z_HTTP_errmsg(hr->code));
  423. odr_write(o, (unsigned char *) sbuf, strlen(sbuf));
  424. /* apply Content-Length if not already applied */
  425. if (!z_HTTP_header_lookup(hr->headers,
  426. "Content-Length"))
  427. {
  428. char lstr[60];
  429. sprintf(lstr, "Content-Length: %d\r\n",
  430. hr->content_len);
  431. odr_write(o, (unsigned char *) lstr, strlen(lstr));
  432. }
  433. for (h = hr->headers; h; h = h->next)
  434. {
  435. odr_write(o, (unsigned char *) h->name, strlen(h->name));
  436. odr_write(o, (unsigned char *) ": ", 2);
  437. odr_write(o, (unsigned char *) h->value, strlen(h->value));
  438. odr_write(o, (unsigned char *) "\r\n", 2);
  439. }
  440. odr_write(o, (unsigned char *) "\r\n", 2);
  441. if (hr->content_buf)
  442. odr_write(o, (unsigned char *)
  443. hr->content_buf,
  444. hr->content_len);
  445. if (o->direction == ODR_PRINT)
  446. {
  447. odr_printf(o, "-- HTTP response:\n%.*s\n", o->top - top0,
  448. o->buf + top0);
  449. odr_printf(o, "-- \n");
  450. }
  451. return 1;
  452. }
  453. int yaz_encode_http_request(ODR o, Z_HTTP_Request *hr)
  454. {
  455. Z_HTTP_Header *h;
  456. int top0 = o->top;
  457. odr_write(o, (unsigned char *) hr->method,
  458. strlen(hr->method));
  459. odr_write(o, (unsigned char *) " ", 1);
  460. odr_write(o, (unsigned char *) hr->path,
  461. strlen(hr->path));
  462. odr_write(o, (unsigned char *) " HTTP/", 6);
  463. odr_write(o, (unsigned char *) hr->version,
  464. strlen(hr->version));
  465. odr_write(o, (unsigned char *) "\r\n", 2);
  466. if (hr->content_len &&
  467. !z_HTTP_header_lookup(hr->headers,
  468. "Content-Length"))
  469. {
  470. char lstr[60];
  471. sprintf(lstr, "Content-Length: %d\r\n",
  472. hr->content_len);
  473. odr_write(o, (unsigned char *) lstr, strlen(lstr));
  474. }
  475. for (h = hr->headers; h; h = h->next)
  476. {
  477. odr_write(o, (unsigned char *) h->name, strlen(h->name));
  478. odr_write(o, (unsigned char *) ": ", 2);
  479. odr_write(o, (unsigned char *) h->value, strlen(h->value));
  480. odr_write(o, (unsigned char *) "\r\n", 2);
  481. }
  482. odr_write(o, (unsigned char *) "\r\n", 2);
  483. if (hr->content_buf)
  484. odr_write(o, (unsigned char *)
  485. hr->content_buf,
  486. hr->content_len);
  487. if (o->direction == ODR_PRINT)
  488. {
  489. odr_printf(o, "-- HTTP request:\n%.*s\n", o->top - top0,
  490. o->buf + top0);
  491. odr_printf(o, "-- \n");
  492. }
  493. return 1;
  494. }
  495. /*
  496. * Local variables:
  497. * c-basic-offset: 4
  498. * c-file-style: "Stroustrup"
  499. * indent-tabs-mode: nil
  500. * End:
  501. * vim: shiftwidth=4 tabstop=8 expandtab
  502. */