📄 connection.c
字号:
/* 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 + -