http_resp.c
上传用户:sun1608
上传日期:2007-02-02
资源大小:6116k
文件大小:13k
源码类别:

流媒体/Mpeg4/MP4

开发平台:

Visual C++

  1. /*
  2.  * The contents of this file are subject to the Mozilla Public
  3.  * License Version 1.1 (the "License"); you may not use this file
  4.  * except in compliance with the License. You may obtain a copy of
  5.  * the License at http://www.mozilla.org/MPL/
  6.  * 
  7.  * Software distributed under the License is distributed on an "AS
  8.  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  9.  * implied. See the License for the specific language governing
  10.  * rights and limitations under the License.
  11.  * 
  12.  * The Original Code is MPEG4IP.
  13.  * 
  14.  * The Initial Developer of the Original Code is Cisco Systems Inc.
  15.  * Portions created by Cisco Systems Inc. are
  16.  * Copyright (C) Cisco Systems Inc. 2001.  All Rights Reserved.
  17.  * 
  18.  * Contributor(s): 
  19.  *              Bill May        wmay@cisco.com
  20.  */
  21. /*
  22.  * http_resp.c - read and decode http response.
  23.  */
  24. #include "systems.h"
  25. #ifdef HAVE_POLL
  26. #include <sys/poll.h>
  27. #endif
  28. #include "http_private.h"
  29. /*
  30.  * http_recv - receive up to len bytes in the buffer
  31.  */
  32. static int http_recv (int server_socket,
  33.       char *buffer,
  34.       uint32_t len)
  35. {
  36.   int ret;
  37. #ifdef HAVE_POLL
  38.   struct pollfd pollit;
  39.   pollit.fd = server_socket;
  40.   pollit.events = POLLIN | POLLPRI;
  41.   pollit.revents = 0;
  42.   ret = poll(&pollit, 1, 2000);
  43. #else
  44.   fd_set read_set;
  45.   struct timeval timeout;
  46.   FD_ZERO(&read_set);
  47.   FD_SET(server_socket, &read_set);
  48.   timeout.tv_sec = 2;
  49.   timeout.tv_usec = 0;
  50.   ret = select(server_socket + 1, &read_set, NULL, NULL, &timeout);
  51. #endif
  52.   if (ret <= 0) {
  53.     return -1;
  54.   }
  55.   ret = recv(server_socket, buffer, len, 0);
  56.   http_debug(LOG_DEBUG, "Return from recv is %d", ret);
  57.   return ret;
  58. }
  59. /*
  60.  * http_read_into_buffer - read bytes into buffer at the buffer offset
  61.  * to the end of the buffer.
  62.  */
  63. static int http_read_into_buffer (http_client_t *cptr,
  64.    uint32_t buffer_offset)
  65. {
  66.   int ret;
  67.   ret = http_recv(cptr->m_server_socket,
  68.   cptr->m_resp_buffer + buffer_offset,
  69.   RESP_BUF_SIZE - buffer_offset);
  70.   if (ret <= 0) return (ret);
  71.   cptr->m_buffer_len = buffer_offset + ret;
  72.   return ret;
  73. }
  74. /*
  75.  * http_get_next_line()
  76.  * Use the existing buffers that we've read, and try to get a coherent
  77.  * line.  This saves having to do a bunch of 1 byte reads looking for a
  78.  * cr/lf - instead, we read as many bytes as we can into the buffer, and
  79.  * then process it.
  80.  */
  81. static const char *http_get_next_line (http_client_t *cptr)
  82. {
  83.   int ret;
  84.   uint32_t ix;
  85.   int last_on;
  86.   /*
  87.    * If we don't have any data, try to read a buffer full
  88.    */
  89.   if (cptr->m_buffer_len <= 0) {
  90.     cptr->m_offset_on = 0;
  91.     ret = http_read_into_buffer(cptr, 0);
  92.     if (ret <= 0) {
  93.       return (NULL);
  94.     }
  95.   }
  96.   /*
  97.    * Look for CR/LF in the buffer.  If we find it, NULL terminate at
  98.    * the CR, then set the buffer values to look past the crlf
  99.    */
  100.   for (ix = cptr->m_offset_on + 1;
  101.        ix < cptr->m_buffer_len;
  102.        ix++) {
  103.     if (cptr->m_resp_buffer[ix] == 'n' &&
  104. cptr->m_resp_buffer[ix - 1] == 'r') {
  105.       const char *retval = &cptr->m_resp_buffer[cptr->m_offset_on];
  106.       cptr->m_offset_on = ix + 1;
  107.       cptr->m_resp_buffer[ix - 1] = ''; // make it easy
  108.       return (retval);
  109.     }
  110.   }
  111.   if (cptr->m_offset_on == 0) {
  112.     return (NULL);
  113.   }
  114.   /*
  115.    * We don't have a line.  So, move the data down in the buffer, then
  116.    * read into the rest of the buffer
  117.    */
  118.   cptr->m_buffer_len -= cptr->m_offset_on;
  119.   if (cptr->m_buffer_len != 0) {
  120.     memmove(cptr->m_resp_buffer,
  121.     &cptr->m_resp_buffer[cptr->m_offset_on],
  122.     cptr->m_buffer_len);
  123.     last_on = cptr->m_buffer_len;
  124.   } else {
  125.     last_on = 1;
  126.   }
  127.   cptr->m_offset_on = 0;
  128.   
  129.   ret = http_read_into_buffer(cptr, cptr->m_buffer_len);
  130.   if (ret <= 0) {
  131.     return (NULL);
  132.   }
  133.   /*
  134.    * Continue searching through the buffer.  If we get this far, we've
  135.    * received like 2K or 4K without a CRLF - most likely a bad response
  136.    */
  137.   for (ix = last_on;
  138.        ix < cptr->m_buffer_len;
  139.        ix++) {
  140.     if (cptr->m_resp_buffer[ix] == 'n' &&
  141. cptr->m_resp_buffer[ix - 1] == 'r') {
  142.       const char *retval = &cptr->m_resp_buffer[cptr->m_offset_on];
  143.       cptr->m_offset_on = ix + 1;
  144.       cptr->m_resp_buffer[ix - 1] = ''; // make it easy
  145.       return (retval);
  146.     }
  147.   }
  148.   return (NULL);
  149. }
  150. /****************************************************************************
  151.  * HTTP header decoding
  152.  ****************************************************************************/
  153. #define HTTP_CMD_DECODE_FUNC(a) static void a(const char *lptr, http_client_t *cptr)
  154. /*
  155.  * Connection: header
  156.  */
  157. HTTP_CMD_DECODE_FUNC(http_cmd_connection)
  158. {
  159.   // connection can be comma seperated list.
  160.   while (*lptr != '') {
  161.     if (strncasecmp(lptr, "close", strlen("close")) == 0) {
  162.       cptr->m_connection_close = 1;
  163.       return;
  164.     } else {
  165.       while (*lptr != '' && *lptr != ',') lptr++;
  166.     }
  167.   }
  168. }
  169. /*
  170.  * Content-length: header
  171.  */
  172. HTTP_CMD_DECODE_FUNC(http_cmd_content_length)
  173. {
  174.   cptr->m_content_len = 0;
  175.   while (isdigit(*lptr)) {
  176.     cptr->m_content_len_received = 1;
  177.     cptr->m_content_len *= 10;
  178.     cptr->m_content_len += *lptr - '0';
  179.     lptr++;
  180.   }
  181. }
  182. /*
  183.  * Content-type: header
  184.  */
  185. HTTP_CMD_DECODE_FUNC(http_cmd_content_type)
  186. {
  187.   FREE_CHECK(cptr->m_resp, content_type);
  188.   cptr->m_resp->content_type = strdup(lptr);
  189. }
  190. /*
  191.  * Location: header
  192.  */
  193. HTTP_CMD_DECODE_FUNC(http_cmd_location)
  194. {
  195.   FREE_CHECK(cptr, m_redir_location);
  196.   cptr->m_redir_location = strdup(lptr);
  197. }
  198. /*
  199.  * Transfer-Encoding: header
  200.  */
  201. HTTP_CMD_DECODE_FUNC(http_cmd_transfer_encoding)
  202. {
  203.   do {
  204.     if (strncasecmp(lptr, "chunked", strlen("chunked")) == 0) {
  205.       cptr->m_transfer_encoding_chunked = 1;
  206.       return;
  207.     }
  208.     while ((*lptr != '') && (*lptr != ';')) lptr++;
  209.     ADV_SPACE(lptr);
  210.   } while (*lptr != '');
  211. }
  212. static struct {
  213.   const char *val;
  214.   uint32_t val_length;
  215.   void (*parse_routine)(const char *lptr, http_client_t *cptr);
  216. } header_types[] =
  217. {
  218. #define HEAD_TYPE(a, b) { a, sizeof(a), b }
  219.   HEAD_TYPE("connection", http_cmd_connection),
  220.   HEAD_TYPE("content-length", http_cmd_content_length),
  221.   HEAD_TYPE("content-type", http_cmd_content_type),
  222.   HEAD_TYPE("location", http_cmd_location),
  223.   HEAD_TYPE("transfer-encoding", http_cmd_transfer_encoding),
  224.   {NULL, 0, NULL },
  225. };
  226. static void http_decode_header (http_client_t *cptr, const char *lptr)
  227. {
  228.   int ix;
  229.   const char *after;
  230.   ix = 0;
  231.   ADV_SPACE(lptr);
  232.   
  233.   while (header_types[ix].val != NULL) {
  234.     if (strncasecmp(lptr,
  235.     header_types[ix].val,
  236.     header_types[ix].val_length - 1) == 0) {
  237.       after = lptr + header_types[ix].val_length - 1;
  238.       ADV_SPACE(after);
  239.       if (*after == ':') {
  240. after++;
  241. ADV_SPACE(after);
  242. /*
  243.  * Call the correct parsing routine
  244.  */
  245. (header_types[ix].parse_routine)(after, cptr);
  246. return;
  247.       }
  248.     }
  249.     ix++;
  250.   }
  251.   //rtsp_debug(LOG_DEBUG, "Not processing response header: %s", lptr);
  252. }
  253. static uint32_t to_hex (const char **hex_string)
  254. {
  255.   const char *p = *hex_string;
  256.   uint32_t ret = 0;
  257.   while (isxdigit(*p)) {
  258.     ret *= 16;
  259.     if (isdigit(*p)) {
  260.       ret += *p - '0';
  261.     } else {
  262.       ret += tolower(*p) - 'a' + 10;
  263.     }
  264.     p++;
  265.   }
  266.   *hex_string = p;
  267.   return (ret);
  268. }
  269. /*
  270.  * http_get_response - get the response, process it, and fill in the response
  271.  * structure.
  272.  */
  273. int http_get_response (http_client_t *cptr,
  274.        http_resp_t **resp)
  275. {
  276.   const char *p;
  277.   int resp_code;
  278.   int ix;
  279.   int done;
  280.   uint32_t len;
  281.   int ret;
  282.   /*
  283.    * Clear out old response header
  284.    */
  285.   if (*resp != NULL) {
  286.     cptr->m_resp = *resp;
  287.     http_resp_clear(*resp);
  288.   } else {
  289.     cptr->m_resp = (http_resp_t *)malloc(sizeof(http_resp_t));
  290.     memset(cptr->m_resp, 0, sizeof(http_resp_t));
  291.     *resp = cptr->m_resp;
  292.   }
  293.   /*
  294.    * Reset all relevent variables
  295.    */
  296.   FREE_CHECK(cptr, m_redir_location);
  297.   cptr->m_connection_close = 0;
  298.   cptr->m_content_len_received = 0;
  299.   cptr->m_offset_on = 0;
  300.   cptr->m_buffer_len = 0;
  301.   cptr->m_transfer_encoding_chunked = 0;
  302.   /*
  303.    * Get the first line and process it
  304.    */
  305.   p = http_get_next_line(cptr);
  306.   if (p == NULL) {
  307.     return (-1);
  308.   }
  309.   /*
  310.    * http/version.version processing
  311.    */
  312.   ADV_SPACE(p);
  313.   if (*p == '' || strncasecmp(p, "http/", strlen("http/")) != 0) {
  314.     return (-1);
  315.   }
  316.   p += strlen("http/");
  317.   ADV_SPACE(p);
  318.   while (*p != '' && isdigit(*p)) p++;
  319.   if (*p++ != '.') return (-1);
  320.   while (*p != '' && isdigit(*p)) p++;
  321.   if (*p++ == '') return (-1);
  322.   ADV_SPACE(p);
  323.   /*
  324.    * error code processing - 200 is gold
  325.    */
  326.   resp_code = 0;
  327.   for (ix = 0; ix < 3; ix++) {
  328.     if (isdigit(*p)) {
  329.       resp_code *= 10;
  330.       resp_code += *p++ - '0';
  331.     } else {
  332.       return (-1);
  333.     }
  334.   }
  335.   (*resp)->ret_code = resp_code;
  336.   ADV_SPACE(p);
  337.   if (*p != '') {
  338.     (*resp)->resp_phrase = strdup(p);
  339.   }
  340.   /*
  341.    * Now begin processing the headers
  342.    */
  343.   done = 0;
  344.   do {
  345.     p = http_get_next_line(cptr);
  346.     if (p == NULL) {
  347.       return (-1);
  348.     }
  349.     if (*p == '') {
  350.       done = 1;
  351.     } else {
  352.       http_debug(LOG_DEBUG, p);
  353.       // we have a header.  See if we want to process it...
  354.       http_decode_header(cptr, p);
  355.     }
  356.   } while (done == 0);
  357.   // Okay - at this point - we have the headers done.  Let's
  358.   // read the body
  359.   if (cptr->m_content_len_received != 0) {
  360.     /*
  361.      * We have content-length - read that many bytes.
  362.      */
  363.     if (cptr->m_content_len != 0) {
  364.       cptr->m_resp->body = (char *)malloc(cptr->m_content_len + 1);
  365.       len = cptr->m_buffer_len - cptr->m_offset_on;
  366.       memcpy(cptr->m_resp->body,
  367.      &cptr->m_resp_buffer[cptr->m_offset_on],
  368.      MIN(len, cptr->m_content_len));
  369.       while (len < cptr->m_content_len) {
  370. ret = http_read_into_buffer(cptr, 0);
  371. if (ret <= 0) {
  372.   return (-1);
  373. memcpy(cptr->m_resp->body + len,
  374.        cptr->m_resp_buffer,
  375.        MIN(cptr->m_content_len - len, cptr->m_buffer_len));
  376. len += cptr->m_buffer_len;
  377.       }
  378.       cptr->m_resp->body[cptr->m_content_len] = '';
  379.       cptr->m_resp->body_len = cptr->m_content_len;
  380.     }
  381.   } else if (cptr->m_transfer_encoding_chunked != 0) {
  382.     /*
  383.      * Chunk encoded - size in hex, body, size in hex, body, 0
  384.      */
  385.     // read a line,
  386.     uint32_t te_size;
  387.     p = http_get_next_line(cptr);
  388.     if (p == NULL) {
  389.       http_debug(LOG_ALERT, "no chunk size reading chunk transitions");
  390.       return (-1);
  391.     }
  392.     te_size = to_hex(&p);
  393.     cptr->m_resp->body = NULL;
  394.     cptr->m_resp->body_len = 0;
  395.     /*
  396.      * Read a te_size chunk of bytes, read CRLF at end of that many bytes,
  397.      * read next size
  398.      */
  399.     while (te_size != 0) {
  400.       http_debug(LOG_DEBUG, "Chunk size %d", te_size);
  401.       cptr->m_resp->body = (char *)realloc(cptr->m_resp->body,
  402.    cptr->m_resp->body_len + te_size);
  403.       len = MIN(te_size, cptr->m_buffer_len - cptr->m_offset_on);
  404.       memcpy(cptr->m_resp->body + cptr->m_resp->body_len,
  405.      &cptr->m_resp_buffer[cptr->m_offset_on],
  406.      len);
  407.       cptr->m_offset_on += len;
  408.       cptr->m_resp->body_len += len;
  409.       http_debug(LOG_DEBUG, "chunk - copied %d from rest of buffer(%d)",
  410.  len, cptr->m_resp->body_len);
  411.       while (len < te_size) {
  412. int ret;
  413. ret = http_recv(cptr->m_server_socket,
  414. cptr->m_resp->body + cptr->m_resp->body_len,
  415. te_size - len);
  416. if (ret <= 0) return (-1);
  417. len += ret;
  418. cptr->m_resp->body_len += ret;
  419. http_debug(LOG_DEBUG, "chunk - recved %d bytes (%d)",
  420.    ret, cptr->m_resp->body_len);
  421.       }
  422.       p = http_get_next_line(cptr); // should read CRLF at end
  423.       if (p == NULL || *p != '') {
  424. http_debug(LOG_ALERT, "Http chunk reader - should be CRLF at end of chunk, is %s", p);
  425. return (-1);
  426.       }
  427.       p = http_get_next_line(cptr); // read next size
  428.       if (p == NULL) {
  429. http_debug(LOG_ALERT,"No chunk size after first");
  430. return (-1);
  431.       }
  432.       te_size = to_hex(&p);
  433.     }
  434.   } else {
  435.     // No termination - just keep reading, I guess...
  436.     len = cptr->m_buffer_len - cptr->m_offset_on;
  437.     cptr->m_resp->body = (char *)malloc(len + 1);
  438.     cptr->m_resp->body_len = len;
  439.     memcpy(cptr->m_resp->body,
  440.    &cptr->m_resp_buffer[cptr->m_offset_on],
  441.    len);
  442.     http_debug(LOG_INFO, "Len bytes copied - %d", len);
  443.     while (http_read_into_buffer(cptr, 0) > 0) {
  444.       char *temp;
  445.       len = cptr->m_resp->body_len + cptr->m_buffer_len;
  446.       temp = realloc(cptr->m_resp->body, len + 1);
  447.       if (temp == NULL) {
  448. return -1;
  449.       }
  450.       cptr->m_resp->body = temp;
  451.       memcpy(&cptr->m_resp->body[cptr->m_resp->body_len],
  452.      cptr->m_resp_buffer,
  453.      cptr->m_buffer_len);
  454.       cptr->m_resp->body_len = len;
  455.     http_debug(LOG_INFO, "Len bytes added - %d", len);
  456.     }
  457.     cptr->m_resp->body[cptr->m_resp->body_len] = '';
  458.       
  459.   }
  460.   return (0);
  461. }
  462. /*
  463.  * http_resp_clear - clean out http_resp_t structure
  464.  */
  465. void http_resp_clear (http_resp_t *rptr)
  466. {
  467.   FREE_CHECK(rptr, body);
  468.   FREE_CHECK(rptr, content_type);
  469.   FREE_CHECK(rptr, resp_phrase);
  470. }
  471. /*
  472.  * http_resp_free - clean out http_resp_t and free
  473.  */
  474. void http_resp_free (http_resp_t *rptr)
  475. {
  476.   if (rptr != NULL) {
  477.     http_resp_clear(rptr);
  478.     free(rptr);
  479.   }
  480. }