⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 http_resp.c

📁 MPEG-4编解码的实现(包括MPEG4视音频编解码)
💻 C
字号:
/*
 * The contents of this file are subject to the Mozilla Public
 * License Version 1.1 (the "License"); you may not use this file
 * except in compliance with the License. You may obtain a copy of
 * the License at http://www.mozilla.org/MPL/
 * 
 * Software distributed under the License is distributed on an "AS
 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
 * implied. See the License for the specific language governing
 * rights and limitations under the License.
 * 
 * The Original Code is MPEG4IP.
 * 
 * The Initial Developer of the Original Code is Cisco Systems Inc.
 * Portions created by Cisco Systems Inc. are
 * Copyright (C) Cisco Systems Inc. 2001.  All Rights Reserved.
 * 
 * Contributor(s): 
 *              Bill May        wmay@cisco.com
 */
/*
 * http_resp.c - read and decode http response.
 */
#include "systems.h"
#ifdef HAVE_POLL
#include <sys/poll.h>
#endif
#include "http_private.h"

/*
 * http_recv - receive up to len bytes in the buffer
 */
static int http_recv (int server_socket,
		      char *buffer,
		      uint32_t len)
{
  int ret;
#ifdef HAVE_POLL
  struct pollfd pollit;

  pollit.fd = server_socket;
  pollit.events = POLLIN | POLLPRI;
  pollit.revents = 0;

  ret = poll(&pollit, 1, 2000);
#else
  fd_set read_set;
  struct timeval timeout;
  FD_ZERO(&read_set);
  FD_SET(server_socket, &read_set);
  timeout.tv_sec = 2;
  timeout.tv_usec = 0;
  ret = select(server_socket + 1, &read_set, NULL, NULL, &timeout);
#endif
  if (ret <= 0) {
    return -1;
  }

  ret = recv(server_socket, buffer, len, 0);
  http_debug(LOG_DEBUG, "Return from recv is %d", ret);
  return ret;
}

/*
 * http_read_into_buffer - read bytes into buffer at the buffer offset
 * to the end of the buffer.
 */
static int http_read_into_buffer (http_client_t *cptr,
			   uint32_t buffer_offset)
{
  int ret;

  ret = http_recv(cptr->m_server_socket,
		  cptr->m_resp_buffer + buffer_offset,
		  RESP_BUF_SIZE - buffer_offset);

  if (ret <= 0) return (ret);

  cptr->m_buffer_len = buffer_offset + ret;

  return ret;
}

/*
 * http_get_next_line()
 * Use the existing buffers that we've read, and try to get a coherent
 * line.  This saves having to do a bunch of 1 byte reads looking for a
 * cr/lf - instead, we read as many bytes as we can into the buffer, and
 * then process it.
 */
static const char *http_get_next_line (http_client_t *cptr)
{
  int ret;
  uint32_t ix;
  int last_on;

  /*
   * If we don't have any data, try to read a buffer full
   */
  if (cptr->m_buffer_len <= 0) {
    cptr->m_offset_on = 0;
    ret = http_read_into_buffer(cptr, 0);
    if (ret <= 0) {
      return (NULL);
    }
  }

  /*
   * Look for CR/LF in the buffer.  If we find it, NULL terminate at
   * the CR, then set the buffer values to look past the crlf
   */
  for (ix = cptr->m_offset_on + 1;
       ix < cptr->m_buffer_len;
       ix++) {
    if (cptr->m_resp_buffer[ix] == '\n' &&
	cptr->m_resp_buffer[ix - 1] == '\r') {
      const char *retval = &cptr->m_resp_buffer[cptr->m_offset_on];
      cptr->m_offset_on = ix + 1;
      cptr->m_resp_buffer[ix - 1] = '\0'; // make it easy
      return (retval);
    }
  }

  if (cptr->m_offset_on == 0) {
    return (NULL);
  }

  /*
   * We don't have a line.  So, move the data down in the buffer, then
   * read into the rest of the buffer
   */
  cptr->m_buffer_len -= cptr->m_offset_on;
  if (cptr->m_buffer_len != 0) {
    memmove(cptr->m_resp_buffer,
	    &cptr->m_resp_buffer[cptr->m_offset_on],
	    cptr->m_buffer_len);
    last_on = cptr->m_buffer_len;
  } else {
    last_on = 1;
  }
  cptr->m_offset_on = 0;
  
  ret = http_read_into_buffer(cptr, cptr->m_buffer_len);
  if (ret <= 0) {
    return (NULL);
  }

  /*
   * Continue searching through the buffer.  If we get this far, we've
   * received like 2K or 4K without a CRLF - most likely a bad response
   */
  for (ix = last_on;
       ix < cptr->m_buffer_len;
       ix++) {
    if (cptr->m_resp_buffer[ix] == '\n' &&
	cptr->m_resp_buffer[ix - 1] == '\r') {
      const char *retval = &cptr->m_resp_buffer[cptr->m_offset_on];
      cptr->m_offset_on = ix + 1;
      cptr->m_resp_buffer[ix - 1] = '\0'; // make it easy
      return (retval);
    }
  }
  return (NULL);
}

/****************************************************************************
 * HTTP header decoding
 ****************************************************************************/

#define HTTP_CMD_DECODE_FUNC(a) static void a(const char *lptr, http_client_t *cptr)

/*
 * Connection: header
 */
HTTP_CMD_DECODE_FUNC(http_cmd_connection)
{
  // connection can be comma seperated list.
  while (*lptr != '\0') {
    if (strncasecmp(lptr, "close", strlen("close")) == 0) {
      cptr->m_connection_close = 1;
      return;
    } else {
      while (*lptr != '\0' && *lptr != ',') lptr++;
    }
  }
}

/*
 * Content-length: header
 */
HTTP_CMD_DECODE_FUNC(http_cmd_content_length)
{
  cptr->m_content_len = 0;
  while (isdigit(*lptr)) {
    cptr->m_content_len_received = 1;
    cptr->m_content_len *= 10;
    cptr->m_content_len += *lptr - '0';
    lptr++;
  }
}

/*
 * Content-type: header
 */
HTTP_CMD_DECODE_FUNC(http_cmd_content_type)
{
  FREE_CHECK(cptr->m_resp, content_type);
  cptr->m_resp->content_type = strdup(lptr);
}

/*
 * Location: header
 */
HTTP_CMD_DECODE_FUNC(http_cmd_location)
{
  FREE_CHECK(cptr, m_redir_location);
  cptr->m_redir_location = strdup(lptr);
}

/*
 * Transfer-Encoding: header
 */
HTTP_CMD_DECODE_FUNC(http_cmd_transfer_encoding)
{
  do {
    if (strncasecmp(lptr, "chunked", strlen("chunked")) == 0) {
      cptr->m_transfer_encoding_chunked = 1;
      return;
    }
    while ((*lptr != '\0') && (*lptr != ';')) lptr++;
    ADV_SPACE(lptr);
  } while (*lptr != '\0');
}

static struct {
  const char *val;
  uint32_t val_length;
  void (*parse_routine)(const char *lptr, http_client_t *cptr);
} header_types[] =
{
#define HEAD_TYPE(a, b) { a, sizeof(a), b }
  HEAD_TYPE("connection", http_cmd_connection),
  HEAD_TYPE("content-length", http_cmd_content_length),
  HEAD_TYPE("content-type", http_cmd_content_type),
  HEAD_TYPE("location", http_cmd_location),
  HEAD_TYPE("transfer-encoding", http_cmd_transfer_encoding),
  {NULL, 0, NULL },
};

static void http_decode_header (http_client_t *cptr, const char *lptr)
{
  int ix;
  const char *after;

  ix = 0;
  ADV_SPACE(lptr);
  
  while (header_types[ix].val != NULL) {
    if (strncasecmp(lptr,
		    header_types[ix].val,
		    header_types[ix].val_length - 1) == 0) {
      after = lptr + header_types[ix].val_length - 1;
      ADV_SPACE(after);
      if (*after == ':') {
	after++;
	ADV_SPACE(after);
	/*
	 * Call the correct parsing routine
	 */
	(header_types[ix].parse_routine)(after, cptr);
	return;
      }
    }
    ix++;
  }

  //rtsp_debug(LOG_DEBUG, "Not processing response header: %s", lptr);
}

static uint32_t to_hex (const char **hex_string)
{
  const char *p = *hex_string;
  uint32_t ret = 0;
  while (isxdigit(*p)) {
    ret *= 16;
    if (isdigit(*p)) {
      ret += *p - '0';
    } else {
      ret += tolower(*p) - 'a' + 10;
    }
    p++;
  }
  *hex_string = p;
  return (ret);
}

/*
 * http_get_response - get the response, process it, and fill in the response
 * structure.
 */
int http_get_response (http_client_t *cptr,
		       http_resp_t **resp)
{
  const char *p;
  int resp_code;
  int ix;
  int done;
  uint32_t len;
  int ret;

  /*
   * Clear out old response header
   */
  if (*resp != NULL) {
    cptr->m_resp = *resp;
    http_resp_clear(*resp);
  } else {
    cptr->m_resp = (http_resp_t *)malloc(sizeof(http_resp_t));
    memset(cptr->m_resp, 0, sizeof(http_resp_t));
    *resp = cptr->m_resp;
  }

  /*
   * Reset all relevent variables
   */
  FREE_CHECK(cptr, m_redir_location);
  cptr->m_connection_close = 0;
  cptr->m_content_len_received = 0;
  cptr->m_offset_on = 0;
  cptr->m_buffer_len = 0;
  cptr->m_transfer_encoding_chunked = 0;

  /*
   * Get the first line and process it
   */
  p = http_get_next_line(cptr);
  if (p == NULL) {
    return (-1);
  }

  /*
   * http/version.version processing
   */
  ADV_SPACE(p);
  if (*p == '\0' || strncasecmp(p, "http/", strlen("http/")) != 0) {
    return (-1);
  }
  p += strlen("http/");
  ADV_SPACE(p);
  while (*p != '\0' && isdigit(*p)) p++;
  if (*p++ != '.') return (-1);
  while (*p != '\0' && isdigit(*p)) p++;
  if (*p++ == '\0') return (-1);
  ADV_SPACE(p);

  /*
   * error code processing - 200 is gold
   */
  resp_code = 0;
  for (ix = 0; ix < 3; ix++) {
    if (isdigit(*p)) {
      resp_code *= 10;
      resp_code += *p++ - '0';
    } else {
      return (-1);
    }
  }
  (*resp)->ret_code = resp_code;
  ADV_SPACE(p);
  if (*p != '\0') {
    (*resp)->resp_phrase = strdup(p);
  }

  /*
   * Now begin processing the headers
   */
  done = 0;
  do {
    p = http_get_next_line(cptr);
    if (p == NULL) {
      return (-1);
    }
    if (*p == '\0') {
      done = 1;
    } else {
      http_debug(LOG_DEBUG, p);
      // we have a header.  See if we want to process it...
      http_decode_header(cptr, p);
    }
  } while (done == 0);

  // Okay - at this point - we have the headers done.  Let's
  // read the body
  if (cptr->m_content_len_received != 0) {
    /*
     * We have content-length - read that many bytes.
     */
    if (cptr->m_content_len != 0) {
      cptr->m_resp->body = (char *)malloc(cptr->m_content_len + 1);
      len = cptr->m_buffer_len - cptr->m_offset_on;
      memcpy(cptr->m_resp->body,
	     &cptr->m_resp_buffer[cptr->m_offset_on],
	     MIN(len, cptr->m_content_len));
      while (len < cptr->m_content_len) {
	ret = http_read_into_buffer(cptr, 0);
	if (ret <= 0) {
	  return (-1);
	} 
	memcpy(cptr->m_resp->body + len,
	       cptr->m_resp_buffer,
	       MIN(cptr->m_content_len - len, cptr->m_buffer_len));
	len += cptr->m_buffer_len;
      }
      cptr->m_resp->body[cptr->m_content_len] = '\0';
      cptr->m_resp->body_len = cptr->m_content_len;
    }
  } else if (cptr->m_transfer_encoding_chunked != 0) {
    /*
     * Chunk encoded - size in hex, body, size in hex, body, 0
     */
    // read a line,
    uint32_t te_size;
    p = http_get_next_line(cptr);
    if (p == NULL) {
      http_debug(LOG_ALERT, "no chunk size reading chunk transitions");
      return (-1);
    }
    te_size = to_hex(&p);
    cptr->m_resp->body = NULL;
    cptr->m_resp->body_len = 0;
    /*
     * Read a te_size chunk of bytes, read CRLF at end of that many bytes,
     * read next size
     */
    while (te_size != 0) {
      http_debug(LOG_DEBUG, "Chunk size %d", te_size);
      cptr->m_resp->body = (char *)realloc(cptr->m_resp->body,
					   cptr->m_resp->body_len + te_size);
      len = MIN(te_size, cptr->m_buffer_len - cptr->m_offset_on);
      memcpy(cptr->m_resp->body + cptr->m_resp->body_len,
	     &cptr->m_resp_buffer[cptr->m_offset_on],
	     len);
      cptr->m_offset_on += len;
      cptr->m_resp->body_len += len;
      http_debug(LOG_DEBUG, "chunk - copied %d from rest of buffer(%d)",
		 len, cptr->m_resp->body_len);
      while (len < te_size) {
	int ret;
	ret = http_recv(cptr->m_server_socket,
			cptr->m_resp->body + cptr->m_resp->body_len,
			te_size - len);
	if (ret <= 0) return (-1);
	len += ret;
	cptr->m_resp->body_len += ret;
	http_debug(LOG_DEBUG, "chunk - recved %d bytes (%d)",
		   ret, cptr->m_resp->body_len);
      }
      p = http_get_next_line(cptr); // should read CRLF at end
      if (p == NULL || *p != '\0') {
	http_debug(LOG_ALERT, "Http chunk reader - should be CRLF at end of chunk, is %s", p);
	return (-1);
      }
      p = http_get_next_line(cptr); // read next size
      if (p == NULL) {
	http_debug(LOG_ALERT,"No chunk size after first");
	return (-1);
      }
      te_size = to_hex(&p);
    }
	
  } else {
    // No termination - just keep reading, I guess...
    len = cptr->m_buffer_len - cptr->m_offset_on;
    cptr->m_resp->body = (char *)malloc(len + 1);
    cptr->m_resp->body_len = len;
    memcpy(cptr->m_resp->body,
	   &cptr->m_resp_buffer[cptr->m_offset_on],
	   len);
    http_debug(LOG_INFO, "Len bytes copied - %d", len);
    while (http_read_into_buffer(cptr, 0) > 0) {
      char *temp;
      len = cptr->m_resp->body_len + cptr->m_buffer_len;
      temp = realloc(cptr->m_resp->body, len + 1);
      if (temp == NULL) {
	return -1;
      }
      cptr->m_resp->body = temp;
      memcpy(&cptr->m_resp->body[cptr->m_resp->body_len],
	     cptr->m_resp_buffer,
	     cptr->m_buffer_len);
      cptr->m_resp->body_len = len;
    http_debug(LOG_INFO, "Len bytes added - %d", len);
    }
    cptr->m_resp->body[cptr->m_resp->body_len] = '\0';
      
  }
  return (0);
}

/*
 * http_resp_clear - clean out http_resp_t structure
 */
void http_resp_clear (http_resp_t *rptr)
{
  FREE_CHECK(rptr, body);
  FREE_CHECK(rptr, content_type);
  FREE_CHECK(rptr, resp_phrase);
}

/*
 * http_resp_free - clean out http_resp_t and free
 */
void http_resp_free (http_resp_t *rptr)
{
  if (rptr != NULL) {
    http_resp_clear(rptr);
    free(rptr);
  }
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -