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

📄 connection.c

📁 一个 http 服务器的框架实现
💻 C
📖 第 1 页 / 共 3 页
字号:
/*     This file is part of libmicrohttpd     (C) 2007 Daniel Pittman and Christian Grothoff     libmicrohttpd is free software; you can redistribute it and/or modify     it under the terms of the GNU General Public License as published     by the Free Software Foundation; either version 2, or (at your     option) any later version.     libmicrohttpd is distributed in the hope that it will be useful, but     WITHOUT ANY WARRANTY; without even the implied warranty of     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     General Public License for more details.     You should have received a copy of the GNU General Public License     along with libmicrohttpd; see the file COPYING.  If not, write to the     Free Software Foundation, Inc., 59 Temple Place - Suite 330,     Boston, MA 02111-1307, USA.*//** * @file connection.c * @brief  Methods for managing connections * @author Daniel Pittman * @author Christian Grothoff */#include "internal.h"#include "connection.h"#include "memorypool.h"#include "response.h"/** * Message to transmit when http 1.1 request is received */#define HTTP_100_CONTINUE "HTTP/1.1 100 Continue\r\n\r\n"/** * Response used when the request (http header) is too big to * be processed. */#define REQUEST_TOO_BIG ""/** * Get all of the headers from the request. * * @param iterator callback to call on each header; *        maybe NULL (then just count headers) * @param iterator_cls extra argument to iterator * @return number of entries iterated over */intMHD_get_connection_values (struct MHD_Connection *connection,                           enum MHD_ValueKind kind,                           MHD_KeyValueIterator iterator, void *iterator_cls){  int ret;  struct MHD_HTTP_Header *pos;  if (connection == NULL)    return -1;  ret = 0;  pos = connection->headers_received;  while (pos != NULL)    {      if (0 != (pos->kind & kind))        {          ret++;          if ((iterator != NULL) &&              (MHD_YES != iterator (iterator_cls,                                    kind, pos->header, pos->value)))            return ret;        }      pos = pos->next;    }  return ret;}/** * Get a particular header value.  If multiple * values match the kind, return any one of them. * * @param key the header to look for * @return NULL if no such item was found */const char *MHD_lookup_connection_value (struct MHD_Connection *connection,                             enum MHD_ValueKind kind, const char *key){  struct MHD_HTTP_Header *pos;  if (connection == NULL)    return NULL;  pos = connection->headers_received;  while (pos != NULL)    {      if ((0 != (pos->kind & kind)) && (0 == strcasecmp (key, pos->header)))        return pos->value;      pos = pos->next;    }  return NULL;}/** * Queue a response to be transmitted to the client (as soon as * possible). * * @param connection the connection identifying the client * @param status_code HTTP status code (i.e. 200 for OK) * @param response response to transmit * @return MHD_NO on error (i.e. reply already sent), *         MHD_YES on success or if message has been queued */intMHD_queue_response (struct MHD_Connection *connection,                    unsigned int status_code, struct MHD_Response *response){  if ((connection == NULL) ||      (response == NULL) ||      (connection->response != NULL) ||      (connection->bodyReceived == 0) || (connection->headersReceived == 0))    return MHD_NO;  MHD_increment_response_rc (response);  connection->response = response;  connection->responseCode = status_code;  if ((connection->method != NULL) &&      (0 == strcasecmp (connection->method, MHD_HTTP_METHOD_HEAD)))    {      /* if this is a "HEAD" request, pretend that we         have already sent the full message body */      connection->messagePos = response->total_size;    }  return MHD_YES;}/** * Do we (still) need to send a 100 continue * message for this connection? */static intMHD_need_100_continue (struct MHD_Connection *connection){  const char *expect;  return ((connection->version != NULL) &&          (0 == strcasecmp (connection->version,                            MHD_HTTP_VERSION_1_1)) &&          (connection->headersReceived == 1) &&          (NULL != (expect = MHD_lookup_connection_value (connection,                                                          MHD_HEADER_KIND,                                                          MHD_HTTP_HEADER_EXPECT)))          && (0 == strcasecmp (expect, "100-continue"))          && (connection->continuePos < strlen (HTTP_100_CONTINUE)));}/** * Obtain the select sets for this connection * * @return MHD_YES on success */intMHD_connection_get_fdset (struct MHD_Connection *connection,                          fd_set * read_fd_set,                          fd_set * write_fd_set,                          fd_set * except_fd_set, int *max_fd){  int fd;  void *buf;  fd = connection->socket_fd;  if (fd == -1)    return MHD_YES;  if ((connection->read_close == MHD_NO) &&      ((connection->headersReceived == 0) ||       (connection->readLoc < connection->read_buffer_size)))    {      FD_SET (fd, read_fd_set);      if (fd > *max_fd)        *max_fd = fd;    }  else    {      if ((connection->read_close == MHD_NO) &&          ((connection->headersReceived == 1) &&           (connection->post_processed == MHD_NO) &&           (connection->readLoc == connection->read_buffer_size)))        {          /* try growing the read buffer, just in case */          buf = MHD_pool_reallocate (connection->pool,                                     connection->read_buffer,                                     connection->read_buffer_size,                                     connection->read_buffer_size * 2 +                                     MHD_BUF_INC_SIZE);          if (buf != NULL)            {              /* we can actually grow the buffer, do it! */              connection->read_buffer = buf;              connection->read_buffer_size =                connection->read_buffer_size * 2 + MHD_BUF_INC_SIZE;              FD_SET (fd, read_fd_set);              if (fd > *max_fd)                *max_fd = fd;            }        }    }  if ((connection->response != NULL) || MHD_need_100_continue (connection))    {      FD_SET (fd, write_fd_set);      if (fd > *max_fd)        *max_fd = fd;    }  return MHD_YES;}/** * We ran out of memory processing the * header.  Handle it properly by stopping to read data * and sending a HTTP 413 or HTTP 414 response. *  * @param status_code the response code to send (413 or 414) */static voidMHD_excessive_data_handler (struct MHD_Connection *connection,                            unsigned int status_code){  struct MHD_Response *response;  /* die, header far too long to be reasonable;     FIXME: send proper response to client     (stop reading, queue proper response) */  connection->read_close = MHD_YES;  connection->headersReceived = MHD_YES;  connection->bodyReceived = MHD_YES;  MHD_DLOG (connection->daemon,            "Received excessively long header, closing connection.\n");  response = MHD_create_response_from_data (strlen (REQUEST_TOO_BIG),                                            REQUEST_TOO_BIG, MHD_NO, MHD_NO);  MHD_queue_response (connection, status_code, response);  MHD_destroy_response (response);}/** * Parse a single line of the HTTP header.  Advance * read_buffer (!) appropriately.  If the current line does not * fit, consider growing the buffer.  If the line is * far too long, close the connection.  If no line is * found (incomplete, buffer too small, line too long), * return NULL.  Otherwise return a pointer to the line. */static char *MHD_get_next_header_line (struct MHD_Connection *connection){  char *rbuf;  size_t pos;  if (connection->readLoc == 0)    return NULL;  pos = 0;  rbuf = connection->read_buffer;  while ((pos < connection->readLoc - 1) &&         (rbuf[pos] != '\r') && (rbuf[pos] != '\n'))    pos++;  if (pos == connection->readLoc - 1)    {      /* not found, consider growing... */      if (connection->readLoc == connection->read_buffer_size)        {          rbuf = MHD_pool_reallocate (connection->pool,                                      connection->read_buffer,                                      connection->read_buffer_size,                                      connection->read_buffer_size * 2 +                                      MHD_BUF_INC_SIZE);          if (rbuf == NULL)            {              MHD_excessive_data_handler (connection,                                          (connection->url != NULL)                                          ? MHD_HTTP_REQUEST_ENTITY_TOO_LARGE                                          : MHD_HTTP_REQUEST_URI_TOO_LONG);            }          else            {              connection->read_buffer_size =                connection->read_buffer_size * 2 + MHD_BUF_INC_SIZE;              connection->read_buffer = rbuf;            }        }      return NULL;    }  /* found, check if we have proper CRLF */  if ((rbuf[pos] == '\r') && (rbuf[pos + 1] == '\n'))    rbuf[pos++] = '\0';         /* skip both r and n */  rbuf[pos++] = '\0';  connection->read_buffer += pos;  connection->read_buffer_size -= pos;  connection->readLoc -= pos;  return rbuf;}/** * @return MHD_NO on failure (out of memory), MHD_YES for success */static intMHD_connection_add_header (struct MHD_Connection *connection,                           char *key, char *value, enum MHD_ValueKind kind){  struct MHD_HTTP_Header *hdr;  hdr = MHD_pool_allocate (connection->pool,                           sizeof (struct MHD_HTTP_Header), MHD_YES);  if (hdr == NULL)    {      MHD_DLOG (connection->daemon,                "Not enough memory to allocate header record!\n");      MHD_excessive_data_handler (connection,                                  MHD_HTTP_REQUEST_ENTITY_TOO_LARGE);      return MHD_NO;    }  hdr->next = connection->headers_received;  hdr->header = key;  hdr->value = value;  hdr->kind = kind;  connection->headers_received = hdr;  return MHD_YES;}/** * Process escape sequences ('+'=space, %HH) */static voidMHD_http_unescape (char *val){  char *esc;  unsigned int num;  while (NULL != (esc = strstr (val, "+")))    *esc = ' ';  while (NULL != (esc = strstr (val, "%")))    {      if ((1 == sscanf (&esc[1],                        "%2x", &num)) || (1 == sscanf (&esc[1], "%2X", &num)))        {          esc[0] = (unsigned char) num;          memmove (&esc[1], &esc[3], strlen (&esc[3]));        }      val = esc + 1;    }}/** * @return MHD_NO on failure (out of memory), MHD_YES for success */static intparse_arguments (enum MHD_ValueKind kind,                 struct MHD_Connection *connection, char *args){  char *equals;  char *amper;  while (args != NULL)    {      equals = strstr (args, "=");      if (equals == NULL)        return MHD_NO;          /* invalid, ignore */      equals[0] = '\0';      equals++;      amper = strstr (equals, "&");      if (amper != NULL)        {          amper[0] = '\0';          amper++;        }      MHD_http_unescape (args);      MHD_http_unescape (equals);      if (MHD_NO == MHD_connection_add_header (connection,                                               args, equals, kind))        return MHD_NO;      args = amper;    }  return MHD_YES;}/** * Parse the cookie header (see RFC 2109). *  * @return MHD_YES for success, MHD_NO for failure (malformed, out of memory) */static intMHD_parse_cookie_header (struct MHD_Connection *connection){  const char *hdr;  char *cpy;  char *pos;

⌨️ 快捷键说明

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