Webserver+3d print
Embed:
(wiki syntax)
Show/hide line numbers
http_server.c
Go to the documentation of this file.
00001 /** 00002 * @file http_server.c 00003 * @brief HTTP server (HyperText Transfer Protocol) 00004 * 00005 * @section License 00006 * 00007 * Copyright (C) 2010-2017 Oryx Embedded SARL. All rights reserved. 00008 * 00009 * This file is part of CycloneTCP Open. 00010 * 00011 * This program is free software; you can redistribute it and/or 00012 * modify it under the terms of the GNU General Public License 00013 * as published by the Free Software Foundation; either version 2 00014 * of the License, or (at your option) any later version. 00015 * 00016 * This program is distributed in the hope that it will be useful, 00017 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00019 * GNU General Public License for more details. 00020 * 00021 * You should have received a copy of the GNU General Public License 00022 * along with this program; if not, write to the Free Software Foundation, 00023 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00024 * 00025 * @section Description 00026 * 00027 * Using the HyperText Transfer Protocol, the HTTP server delivers web pages 00028 * to browsers as well as other data files to web-based applications. Refers 00029 * to the following RFCs for complete details: 00030 * - RFC 1945: Hypertext Transfer Protocol - HTTP/1.0 00031 * - RFC 2616: Hypertext Transfer Protocol - HTTP/1.1 00032 * - RFC 2617: HTTP Authentication: Basic and Digest Access Authentication 00033 * - RFC 2818: HTTP Over TLS 00034 * 00035 * @author Oryx Embedded SARL (www.oryx-embedded.com) 00036 * @version 1.7.6 00037 **/ 00038 00039 //Switch to the appropriate trace level 00040 #define TRACE_LEVEL HTTP_TRACE_LEVEL 00041 00042 //Dependencies 00043 #include <stdlib.h> 00044 #include "core/net.h" 00045 #include "http/http_server.h" 00046 #include "http/http_server_auth.h" 00047 #include "http/http_server_misc.h" 00048 #include "http/mime.h" 00049 #include "http/ssi.h" 00050 #include "debug.h" 00051 00052 //Check TCP/IP stack configuration 00053 #if (HTTP_SERVER_SUPPORT == ENABLED) 00054 00055 00056 /** 00057 * @brief Initialize settings with default values 00058 * @param[out] settings Structure that contains HTTP server settings 00059 **/ 00060 00061 void httpServerGetDefaultSettings(HttpServerSettings *settings) 00062 { 00063 //The HTTP server is not bound to any interface 00064 settings->interface = NULL; 00065 00066 //Listen to port 80 00067 settings->port = HTTP_PORT; 00068 //Maximum length of the pending connection queue 00069 settings->backlog = HTTP_SERVER_BACKLOG; 00070 //Client connections 00071 settings->maxConnections = 0; 00072 settings->connections = NULL; 00073 //Specify the server's root directory 00074 strcpy(settings->rootDirectory, "/"); 00075 //Set default home page 00076 strcpy(settings->defaultDocument, "index.htm"); 00077 00078 #if (HTTP_SERVER_TLS_SUPPORT == ENABLED) 00079 //SSL/TLS initialization callback function 00080 settings->tlsInitCallback = NULL; 00081 #endif 00082 00083 #if (HTTP_SERVER_BASIC_AUTH_SUPPORT == ENABLED || HTTP_SERVER_DIGEST_AUTH_SUPPORT == ENABLED) 00084 //Random data generation callback function 00085 settings->randCallback = NULL; 00086 //HTTP authentication callback function 00087 settings->authCallback = NULL; 00088 #endif 00089 00090 //CGI callback function 00091 settings->cgiCallback = NULL; 00092 //HTTP request callback function 00093 settings->requestCallback = NULL; 00094 //URI not found callback function 00095 settings->uriNotFoundCallback = NULL; 00096 } 00097 00098 00099 /** 00100 * @brief HTTP server initialization 00101 * @param[in] context Pointer to the HTTP server context 00102 * @param[in] settings HTTP server specific settings 00103 * @return Error code 00104 **/ 00105 00106 error_t httpServerInit(HttpServerContext *context, const HttpServerSettings *settings) 00107 { 00108 error_t error; 00109 uint_t i; 00110 HttpConnection *connection; 00111 00112 //Debug message 00113 TRACE_INFO("Initializing HTTP server...\r\n"); 00114 00115 //Ensure the parameters are valid 00116 if(context == NULL || settings == NULL) 00117 return ERROR_INVALID_PARAMETER; 00118 00119 //Check user settings 00120 if(settings->maxConnections == 0 || settings->connections == NULL) 00121 return ERROR_INVALID_PARAMETER; 00122 00123 //Clear the HTTP server context 00124 memset(context, 0, sizeof(HttpServerContext)); 00125 00126 //Save user settings 00127 context->settings = *settings; 00128 //Client connections 00129 context->connections = settings->connections; 00130 00131 //Create a semaphore to limit the number of simultaneous connections 00132 if(!osCreateSemaphore(&context->semaphore, context->settings.maxConnections)) 00133 return ERROR_OUT_OF_RESOURCES; 00134 00135 //Loop through client connections 00136 for(i = 0; i < context->settings.maxConnections; i++) 00137 { 00138 //Point to the structure representing the client connection 00139 connection = &context->connections[i]; 00140 00141 //Initialize the structure 00142 memset(connection, 0, sizeof(HttpConnection)); 00143 00144 //Create an event object to manage connection lifetime 00145 if(!osCreateEvent(&connection->startEvent)) 00146 return ERROR_OUT_OF_RESOURCES; 00147 } 00148 00149 #if (HTTP_SERVER_DIGEST_AUTH_SUPPORT == ENABLED) 00150 //Create a mutex to prevent simultaneous access to the nonce cache 00151 if(!osCreateMutex(&context->nonceCacheMutex)) 00152 return ERROR_OUT_OF_RESOURCES; 00153 #endif 00154 00155 //Open a TCP socket 00156 context->socket = socketOpen(SOCKET_TYPE_STREAM, SOCKET_IP_PROTO_TCP); 00157 //Failed to open socket? 00158 if(!context->socket) 00159 return ERROR_OPEN_FAILED; 00160 00161 //Set timeout for blocking functions 00162 error = socketSetTimeout(context->socket, INFINITE_DELAY); 00163 //Any error to report? 00164 if(error) 00165 return error; 00166 00167 //Associate the socket with the relevant interface 00168 error = socketBindToInterface(context->socket, settings->interface); 00169 //Unable to bind the socket to the desired interface? 00170 if(error) 00171 return error; 00172 00173 //Bind newly created socket to port 80 00174 error = socketBind(context->socket, &IP_ADDR_ANY, settings->port); 00175 //Failed to bind socket to port 80? 00176 if(error) 00177 return error; 00178 00179 //Place socket in listening state 00180 error = socketListen(context->socket, settings->backlog); 00181 //Any failure to report? 00182 if(error) 00183 return error; 00184 00185 //Successful initialization 00186 return NO_ERROR; 00187 } 00188 00189 00190 /** 00191 * @brief Start HTTP server 00192 * @param[in] context Pointer to the HTTP server context 00193 * @return Error code 00194 **/ 00195 00196 error_t httpServerStart(HttpServerContext *context) 00197 { 00198 uint_t i; 00199 00200 //Debug message 00201 TRACE_INFO("Starting HTTP server...\r\n"); 00202 00203 //Make sure the HTTP server context is valid 00204 if(context == NULL) 00205 return ERROR_INVALID_PARAMETER; 00206 00207 //Loop through client connections 00208 for(i = 0; i < context->settings.maxConnections; i++) 00209 { 00210 //Create a task to service a given HTTP client connection 00211 context->connections[i].taskHandle = osCreateTask("HTTP Connection", 00212 httpConnectionTask, &context->connections[i], 00213 HTTP_SERVER_STACK_SIZE, HTTP_SERVER_PRIORITY); 00214 00215 //Unable to create the task? 00216 if(context->connections[i].taskHandle == OS_INVALID_HANDLE) 00217 return ERROR_OUT_OF_RESOURCES; 00218 } 00219 00220 //Create the HTTP server listener task 00221 context->taskHandle = osCreateTask("HTTP Listener", httpListenerTask, 00222 context, HTTP_SERVER_STACK_SIZE, HTTP_SERVER_PRIORITY); 00223 00224 //Unable to create the task? 00225 if(context->taskHandle == OS_INVALID_HANDLE) 00226 return ERROR_OUT_OF_RESOURCES; 00227 00228 //The HTTP server has successfully started 00229 return NO_ERROR; 00230 } 00231 00232 00233 /** 00234 * @brief HTTP server listener task 00235 * @param[in] param Pointer to the HTTP server context 00236 **/ 00237 00238 void httpListenerTask(void *param) 00239 { 00240 uint_t i; 00241 uint_t counter; 00242 uint16_t clientPort; 00243 IpAddr clientIpAddr; 00244 HttpServerContext *context; 00245 HttpConnection *connection; 00246 Socket *socket; 00247 00248 //Retrieve the HTTP server context 00249 context = (HttpServerContext *) param; 00250 00251 //Process incoming connections to the server 00252 for(counter = 1; ; counter++) 00253 { 00254 //Debug message 00255 TRACE_INFO("Ready to accept a new connection...\r\n"); 00256 00257 //Limit the number of simultaneous connections to the HTTP server 00258 osWaitForSemaphore(&context->semaphore, INFINITE_DELAY); 00259 00260 //Loop through available client connections 00261 for(i = 0; i < context->settings.maxConnections; i++) 00262 { 00263 //Point to the current connection 00264 connection = &context->connections[i]; 00265 00266 //Ready to service the client request? 00267 if(!connection->running) 00268 { 00269 //Accept an incoming connection 00270 socket = socketAccept(context->socket, &clientIpAddr, &clientPort); 00271 00272 //Make sure the socket handle is valid 00273 if(socket != NULL) 00274 { 00275 //Debug message 00276 TRACE_INFO("Connection #%u established with client %s port %" PRIu16 "...\r\n", 00277 counter, ipAddrToString(&clientIpAddr, NULL), clientPort); 00278 00279 //Reference to the HTTP server settings 00280 connection->settings = &context->settings; 00281 //Reference to the HTTP server context 00282 connection->serverContext = context; 00283 //Reference to the new socket 00284 connection->socket = socket; 00285 00286 //Set timeout for blocking functions 00287 socketSetTimeout(connection->socket, HTTP_SERVER_TIMEOUT); 00288 00289 //The client connection task is now running... 00290 connection->running = TRUE; 00291 //Service the current connection request 00292 osSetEvent(&connection->startEvent); 00293 00294 //We are done 00295 break; 00296 } 00297 } 00298 } 00299 } 00300 } 00301 00302 00303 /** 00304 * @brief Task that services requests from an active connection 00305 * @param[in] param Structure representing an HTTP connection with a client 00306 **/ 00307 00308 void httpConnectionTask(void *param) 00309 { 00310 error_t error; 00311 uint_t counter; 00312 HttpConnection *connection; 00313 00314 //Point to the structure representing the HTTP connection 00315 connection = (HttpConnection *) param; 00316 00317 //Endless loop 00318 while(1) 00319 { 00320 //Wait for an incoming connection attempt 00321 osWaitForEvent(&connection->startEvent, INFINITE_DELAY); 00322 00323 //Initialize status code 00324 error = NO_ERROR; 00325 00326 #if (HTTP_SERVER_TLS_SUPPORT == ENABLED) 00327 //Use SSL/TLS to secure the connection? 00328 if(connection->settings->useTls) 00329 { 00330 //Debug message 00331 TRACE_INFO("Initializing SSL/TLS session...\r\n"); 00332 00333 //Start of exception handling block 00334 do 00335 { 00336 //Allocate SSL/TLS context 00337 connection->tlsContext = tlsInit(); 00338 //Initialization failed? 00339 if(connection->tlsContext == NULL) 00340 { 00341 //Report an error 00342 error = ERROR_OUT_OF_MEMORY; 00343 //Exit immediately 00344 break; 00345 } 00346 00347 //Select server operation mode 00348 error = tlsSetConnectionEnd(connection->tlsContext, TLS_CONNECTION_END_SERVER); 00349 //Any error to report? 00350 if(error) 00351 break; 00352 00353 //Bind TLS to the relevant socket 00354 error = tlsSetSocket(connection->tlsContext, connection->socket); 00355 //Any error to report? 00356 if(error) 00357 break; 00358 00359 //Invoke user-defined callback, if any 00360 if(connection->settings->tlsInitCallback != NULL) 00361 { 00362 //Perform SSL/TLS related initialization 00363 error = connection->settings->tlsInitCallback(connection, connection->tlsContext); 00364 //Any error to report? 00365 if(error) 00366 break; 00367 } 00368 00369 //Establish a secure session 00370 error = tlsConnect(connection->tlsContext); 00371 //Any error to report? 00372 if(error) 00373 break; 00374 00375 //End of exception handling block 00376 } while(0); 00377 } 00378 else 00379 { 00380 //Do not use SSL/TLS 00381 connection->tlsContext = NULL; 00382 } 00383 #endif 00384 00385 //Check status code 00386 if(!error) 00387 { 00388 //Process incoming requests 00389 for(counter = 0; counter < HTTP_SERVER_MAX_REQUESTS; counter++) 00390 { 00391 //Debug message 00392 TRACE_INFO("Waiting for request...\r\n"); 00393 00394 //Clear request header 00395 memset(&connection->request, 0, sizeof(HttpRequest)); 00396 //Clear response header 00397 memset(&connection->response, 0, sizeof(HttpResponse)); 00398 00399 //Read the HTTP request header and parse its contents 00400 error = httpReadRequestHeader(connection); 00401 //Any error to report? 00402 if(error) 00403 { 00404 //Debug message 00405 TRACE_INFO("No HTTP request received or parsing error...\r\n"); 00406 break; 00407 } 00408 00409 #if (HTTP_SERVER_BASIC_AUTH_SUPPORT == ENABLED || HTTP_SERVER_DIGEST_AUTH_SUPPORT == ENABLED) 00410 //No Authorization header found? 00411 if(!connection->request.auth.found) 00412 { 00413 //Invoke user-defined callback, if any 00414 if(connection->settings->authCallback != NULL) 00415 { 00416 //Check whether the access to the specified URI is authorized 00417 connection->status = connection->settings->authCallback(connection, 00418 connection->request.auth.user, connection->request.uri); 00419 } 00420 else 00421 { 00422 //Access to the specified URI is allowed 00423 connection->status = HTTP_ACCESS_ALLOWED; 00424 } 00425 } 00426 00427 //Check access status 00428 if(connection->status == HTTP_ACCESS_ALLOWED) 00429 { 00430 //Access to the specified URI is allowed 00431 error = NO_ERROR; 00432 } 00433 else if(connection->status == HTTP_ACCESS_BASIC_AUTH_REQUIRED) 00434 { 00435 //Basic access authentication is required 00436 connection->response.auth.mode = HTTP_AUTH_MODE_BASIC; 00437 //Report an error 00438 error = ERROR_AUTH_REQUIRED; 00439 } 00440 else if(connection->status == HTTP_ACCESS_DIGEST_AUTH_REQUIRED) 00441 { 00442 //Digest access authentication is required 00443 connection->response.auth.mode = HTTP_AUTH_MODE_DIGEST; 00444 //Report an error 00445 error = ERROR_AUTH_REQUIRED; 00446 } 00447 else 00448 { 00449 //Access to the specified URI is denied 00450 error = ERROR_NOT_FOUND; 00451 } 00452 #endif 00453 //Debug message 00454 TRACE_INFO("Sending HTTP response to the client...\r\n"); 00455 00456 //Check status code 00457 if(!error) 00458 { 00459 //Default HTTP header fields 00460 httpInitResponseHeader(connection); 00461 00462 //Invoke user-defined callback, if any 00463 if(connection->settings->requestCallback != NULL) 00464 { 00465 error = connection->settings->requestCallback(connection, 00466 connection->request.uri); 00467 } 00468 else 00469 { 00470 //Keep processing... 00471 error = ERROR_NOT_FOUND; 00472 } 00473 00474 //Check status code 00475 if(error == ERROR_NOT_FOUND) 00476 { 00477 #if (HTTP_SERVER_SSI_SUPPORT == ENABLED) 00478 //Use server-side scripting to dynamically generate HTML code? 00479 if(httpCompExtension(connection->request.uri, ".stm") || 00480 httpCompExtension(connection->request.uri, ".shtm") || 00481 httpCompExtension(connection->request.uri, ".shtml")) 00482 { 00483 //SSI processing (Server Side Includes) 00484 error = ssiExecuteScript(connection, connection->request.uri, 0); 00485 } 00486 else 00487 #endif 00488 { 00489 //Set the maximum age for static resources 00490 connection->response.maxAge = HTTP_SERVER_MAX_AGE; 00491 00492 //Send the contents of the requested page 00493 error = httpSendResponse(connection, connection->request.uri); 00494 } 00495 } 00496 00497 //The requested resource is not available? 00498 if(error == ERROR_NOT_FOUND) 00499 { 00500 //Default HTTP header fields 00501 httpInitResponseHeader(connection); 00502 00503 //Invoke user-defined callback, if any 00504 if(connection->settings->uriNotFoundCallback != NULL) 00505 { 00506 error = connection->settings->uriNotFoundCallback(connection, 00507 connection->request.uri); 00508 } 00509 } 00510 } 00511 00512 //Check status code 00513 if(error) 00514 { 00515 //Default HTTP header fields 00516 httpInitResponseHeader(connection); 00517 00518 //Bad request? 00519 if(error == ERROR_INVALID_REQUEST) 00520 { 00521 //Send an error 400 and close the connection immediately 00522 httpSendErrorResponse(connection, 400, 00523 "The request is badly formed"); 00524 } 00525 //Authorization required? 00526 else if(error == ERROR_AUTH_REQUIRED) 00527 { 00528 //Send an error 401 and keep the connection alive 00529 error = httpSendErrorResponse(connection, 401, 00530 "Authorization required"); 00531 } 00532 //Page not found? 00533 else if(error == ERROR_NOT_FOUND) 00534 { 00535 //Send an error 404 and keep the connection alive 00536 error = httpSendErrorResponse(connection, 404, 00537 "The requested page could not be found"); 00538 } 00539 } 00540 00541 //Internal error? 00542 if(error) 00543 { 00544 //Close the connection immediately 00545 break; 00546 } 00547 00548 //Check whether the connection is persistent or not 00549 if(!connection->request.keepAlive || !connection->response.keepAlive) 00550 { 00551 //Close the connection immediately 00552 break; 00553 } 00554 } 00555 } 00556 00557 #if (HTTP_SERVER_TLS_SUPPORT == ENABLED) 00558 //Valid SSL/TLS context? 00559 if(connection->tlsContext != NULL) 00560 { 00561 //Debug message 00562 TRACE_INFO("Closing SSL/TLS session...\r\n"); 00563 00564 //Gracefully close SSL/TLS session 00565 tlsShutdown(connection->tlsContext); 00566 //Release context 00567 tlsFree(connection->tlsContext); 00568 } 00569 #endif 00570 00571 //Valid socket handle? 00572 if(connection->socket != NULL) 00573 { 00574 //Debug message 00575 TRACE_INFO("Graceful shutdown...\r\n"); 00576 //Graceful shutdown 00577 socketShutdown(connection->socket, SOCKET_SD_BOTH); 00578 00579 //Debug message 00580 TRACE_INFO("Closing socket...\r\n"); 00581 //Close socket 00582 socketClose(connection->socket); 00583 } 00584 00585 //Ready to serve the next connection request... 00586 connection->running = FALSE; 00587 //Release semaphore 00588 osReleaseSemaphore(&connection->serverContext->semaphore); 00589 } 00590 } 00591 00592 00593 /** 00594 * @brief Send HTTP response header 00595 * @param[in] connection Structure representing an HTTP connection 00596 * @return Error code 00597 **/ 00598 00599 error_t httpWriteHeader(HttpConnection *connection) 00600 { 00601 error_t error; 00602 00603 //Format HTTP response header 00604 error = httpFormatResponseHeader(connection, connection->buffer); 00605 00606 //Check status code 00607 if(!error) 00608 { 00609 //Debug message 00610 TRACE_DEBUG("HTTP response header:\r\n%s", connection->buffer); 00611 00612 //Send HTTP response header to the client 00613 error = httpSend(connection, connection->buffer, 00614 strlen(connection->buffer), HTTP_FLAG_DELAY); 00615 } 00616 00617 //Return status code 00618 return error; 00619 } 00620 00621 00622 /** 00623 * @brief Read data from client request 00624 * @param[in] connection Structure representing an HTTP connection 00625 * @param[out] data Buffer where to store the incoming data 00626 * @param[in] size Maximum number of bytes that can be received 00627 * @param[out] received Number of bytes that have been received 00628 * @param[in] flags Set of flags that influences the behavior of this function 00629 * @return Error code 00630 **/ 00631 00632 error_t httpReadStream(HttpConnection *connection, 00633 void *data, size_t size, size_t *received, uint_t flags) 00634 { 00635 error_t error; 00636 size_t n; 00637 00638 //No data has been read yet 00639 *received = 0; 00640 00641 //Chunked encoding transfer is used? 00642 if(connection->request.chunkedEncoding) 00643 { 00644 //Point to the output buffer 00645 char_t *p = data; 00646 00647 //Read as much data as possible 00648 while(*received < size) 00649 { 00650 //End of HTTP request body? 00651 if(connection->request.lastChunk) 00652 return ERROR_END_OF_STREAM; 00653 00654 //Acquire a new chunk when the current chunk 00655 //has been completely consumed 00656 if(connection->request.byteCount == 0) 00657 { 00658 //The size of each chunk is sent right before the chunk itself 00659 error = httpReadChunkSize(connection); 00660 //Failed to decode the chunk-size field? 00661 if(error) 00662 return error; 00663 00664 //Any chunk whose size is zero terminates the data transfer 00665 if(!connection->request.byteCount) 00666 { 00667 //The user must be satisfied with data already on hand 00668 return (*received > 0) ? NO_ERROR : ERROR_END_OF_STREAM; 00669 } 00670 } 00671 00672 //Limit the number of bytes to read at a time 00673 n = MIN(size - *received, connection->request.byteCount); 00674 00675 //Read data 00676 error = httpReceive(connection, p, n, &n, flags); 00677 //Any error to report? 00678 if(error) 00679 return error; 00680 00681 //Total number of data that have been read 00682 *received += n; 00683 //Remaining data still available in the current chunk 00684 connection->request.byteCount -= n; 00685 00686 //The HTTP_FLAG_BREAK_CHAR flag causes the function to stop reading 00687 //data as soon as the specified break character is encountered 00688 if(flags & HTTP_FLAG_BREAK_CRLF) 00689 { 00690 //Check whether a break character has been received 00691 if(p[n - 1] == LSB(flags)) 00692 break; 00693 } 00694 //The HTTP_FLAG_WAIT_ALL flag causes the function to return 00695 //only when the requested number of bytes have been read 00696 else if(!(flags & HTTP_FLAG_WAIT_ALL)) 00697 { 00698 break; 00699 } 00700 00701 //Advance data pointer 00702 p += n; 00703 } 00704 } 00705 //Default encoding? 00706 else 00707 { 00708 //Return immediately if the end of the request body has been reached 00709 if(!connection->request.byteCount) 00710 return ERROR_END_OF_STREAM; 00711 00712 //Limit the number of bytes to read 00713 n = MIN(size, connection->request.byteCount); 00714 00715 //Read data 00716 error = httpReceive(connection, data, n, received, flags); 00717 //Any error to report 00718 if(error) 00719 return error; 00720 00721 //Decrement the count of remaining bytes to read 00722 connection->request.byteCount -= *received; 00723 } 00724 00725 //Successful read operation 00726 return NO_ERROR; 00727 } 00728 00729 00730 /** 00731 * @brief Write data to the client 00732 * @param[in] connection Structure representing an HTTP connection 00733 * @param[in] data Buffer containing the data to be transmitted 00734 * @param[in] length Number of bytes to be transmitted 00735 * @return Error code 00736 **/ 00737 00738 error_t httpWriteStream(HttpConnection *connection, 00739 const void *data, size_t length) 00740 { 00741 error_t error; 00742 uint_t n; 00743 00744 //Use chunked encoding transfer? 00745 if(connection->response.chunkedEncoding) 00746 { 00747 //Any data to send? 00748 if(length > 0) 00749 { 00750 char_t s[8]; 00751 00752 //The chunk-size field is a string of hex digits 00753 //indicating the size of the chunk 00754 n = sprintf(s, "%X\r\n", length); 00755 00756 //Send the chunk-size field 00757 error = httpSend(connection, s, n, HTTP_FLAG_DELAY); 00758 //Failed to send data? 00759 if(error) 00760 return error; 00761 00762 //Send the chunk-data 00763 error = httpSend(connection, data, length, HTTP_FLAG_DELAY); 00764 //Failed to send data? 00765 if(error) 00766 return error; 00767 00768 //Terminate the chunk-data by CRLF 00769 error = httpSend(connection, "\r\n", 2, HTTP_FLAG_DELAY); 00770 } 00771 else 00772 { 00773 //Any chunk whose size is zero may terminate the data 00774 //transfer and must be discarded 00775 error = NO_ERROR; 00776 } 00777 } 00778 //Default encoding? 00779 else 00780 { 00781 //The length of the body shall not exceed the value 00782 //specified in the Content-Length field 00783 length = MIN(length, connection->response.byteCount); 00784 00785 //Send user data 00786 error = httpSend(connection, data, length, HTTP_FLAG_DELAY); 00787 00788 //Decrement the count of remaining bytes to be transferred 00789 connection->response.byteCount -= length; 00790 } 00791 00792 //Return status code 00793 return error; 00794 } 00795 00796 00797 /** 00798 * @brief Close output stream 00799 * @param[in] connection Structure representing an HTTP connection 00800 * @return Error code 00801 **/ 00802 00803 error_t httpCloseStream(HttpConnection *connection) 00804 { 00805 error_t error; 00806 00807 //Use chunked encoding transfer? 00808 if(connection->response.chunkedEncoding) 00809 { 00810 //The chunked encoding is ended by any chunk whose size is zero 00811 error = httpSend(connection, "0\r\n\r\n", 5, HTTP_FLAG_NO_DELAY); 00812 } 00813 else 00814 { 00815 //Flush the send buffer 00816 error = httpSend(connection, "", 0, HTTP_FLAG_NO_DELAY); 00817 } 00818 00819 //Return status code 00820 return error; 00821 } 00822 00823 00824 /** 00825 * @brief Send HTTP response 00826 * @param[in] connection Structure representing an HTTP connection 00827 * @param[in] uri NULL-terminated string containing the file to be sent in response 00828 * @return Error code 00829 **/ 00830 00831 error_t httpSendResponse(HttpConnection *connection, const char_t *uri) 00832 { 00833 #if (HTTP_SERVER_FS_SUPPORT == ENABLED) 00834 error_t error; 00835 uint32_t length; 00836 size_t n; 00837 FsFile *file; 00838 00839 //Retrieve the full pathname 00840 httpGetAbsolutePath(connection, uri, 00841 connection->buffer, HTTP_SERVER_BUFFER_SIZE); 00842 00843 //Retrieve the size of the specified file 00844 error = fsGetFileSize(connection->buffer, &length); 00845 //The specified URI cannot be found? 00846 if(error) 00847 return ERROR_NOT_FOUND; 00848 00849 //Open the file for reading 00850 file = fsOpenFile(connection->buffer, FS_FILE_MODE_READ); 00851 //Failed to open the file? 00852 if(file == NULL) 00853 return ERROR_NOT_FOUND; 00854 #else 00855 error_t error; 00856 size_t length; 00857 uint8_t *data; 00858 00859 //Retrieve the full pathname 00860 httpGetAbsolutePath(connection, uri, 00861 connection->buffer, HTTP_SERVER_BUFFER_SIZE); 00862 00863 //Get the resource data associated with the URI 00864 error = resGetData(connection->buffer, &data, &length); 00865 //The specified URI cannot be found? 00866 if(error) 00867 return error; 00868 #endif 00869 00870 //Format HTTP response header 00871 connection->response.statusCode = 200; 00872 connection->response.contentType = mimeGetType(uri); 00873 connection->response.chunkedEncoding = FALSE; 00874 connection->response.contentLength = length; 00875 00876 //Send the header to the client 00877 error = httpWriteHeader(connection); 00878 //Any error to report? 00879 if(error) 00880 { 00881 #if (HTTP_SERVER_FS_SUPPORT == ENABLED) 00882 //Close the file 00883 fsCloseFile(file); 00884 #endif 00885 //Return status code 00886 return error; 00887 } 00888 00889 #if (HTTP_SERVER_FS_SUPPORT == ENABLED) 00890 //Send response body 00891 while(length > 0) 00892 { 00893 //Limit the number of bytes to read at a time 00894 n = MIN(length, HTTP_SERVER_BUFFER_SIZE); 00895 00896 //Read data from the specified file 00897 error = fsReadFile(file, connection->buffer, n, &n); 00898 //End of input stream? 00899 if(error) 00900 break; 00901 00902 //Send data to the client 00903 error = httpWriteStream(connection, connection->buffer, n); 00904 //Any error to report? 00905 if(error) 00906 break; 00907 00908 //Decrement the count of remaining bytes to be transferred 00909 length -= n; 00910 } 00911 00912 //Close the file 00913 fsCloseFile(file); 00914 00915 //Successful file transfer? 00916 if(error == NO_ERROR || error == ERROR_END_OF_FILE) 00917 { 00918 if(length == 0) 00919 { 00920 //Properly close the output stream 00921 error = httpCloseStream(connection); 00922 } 00923 } 00924 #else 00925 //Send response body 00926 error = httpWriteStream(connection, data, length); 00927 //Any error to report? 00928 if(error) 00929 return error; 00930 00931 //Properly close output stream 00932 error = httpCloseStream(connection); 00933 #endif 00934 00935 //Return status code 00936 return error; 00937 } 00938 00939 00940 /** 00941 * @brief Send error response to the client 00942 * @param[in] connection Structure representing an HTTP connection 00943 * @param[in] statusCode HTTP status code 00944 * @param[in] message User message 00945 * @return Error code 00946 **/ 00947 00948 error_t httpSendErrorResponse(HttpConnection *connection, 00949 uint_t statusCode, const char_t *message) 00950 { 00951 error_t error; 00952 size_t length; 00953 00954 //HTML response template 00955 static const char_t template[] = 00956 "<!doctype html>\r\n" 00957 "<html>\r\n" 00958 "<head><title>Error %03d</title></head>\r\n" 00959 "<body>\r\n" 00960 "<h2>Error %03d</h2>\r\n" 00961 "<p>%s</p>\r\n" 00962 "</body>\r\n" 00963 "</html>\r\n"; 00964 00965 //Compute the length of the response 00966 length = strlen(template) + strlen(message) - 4; 00967 00968 //Format HTTP response header 00969 connection->response.statusCode = statusCode; 00970 connection->response.contentType = mimeGetType(".htm"); 00971 connection->response.chunkedEncoding = FALSE; 00972 connection->response.contentLength = length; 00973 00974 //Send the header to the client 00975 error = httpWriteHeader(connection); 00976 //Any error to report? 00977 if(error) 00978 return error; 00979 00980 //Format HTML response 00981 sprintf(connection->buffer, template, statusCode, statusCode, message); 00982 00983 //Send response body 00984 error = httpWriteStream(connection, connection->buffer, length); 00985 //Any error to report? 00986 if(error) 00987 return error; 00988 00989 //Properly close output stream 00990 error = httpCloseStream(connection); 00991 //Return status code 00992 return error; 00993 } 00994 00995 00996 /** 00997 * @brief Send redirect response to the client 00998 * @param[in] connection Structure representing an HTTP connection 00999 * @param[in] statusCode HTTP status code (301 for permanent redirects) 01000 * @param[in] uri NULL-terminated string containing the redirect URI 01001 * @return Error code 01002 **/ 01003 01004 error_t httpSendRedirectResponse(HttpConnection *connection, 01005 uint_t statusCode, const char_t *uri) 01006 { 01007 error_t error; 01008 size_t length; 01009 01010 //HTML response template 01011 static const char_t template[] = 01012 "<!doctype html>\r\n" 01013 "<html>\r\n" 01014 "<head><title>Moved</title></head>\r\n" 01015 "<body>\r\n" 01016 "<h2>Moved</h2>\r\n" 01017 "<p>This page has moved to <a href=\"%s\">%s</a>.</p>" 01018 "</body>\r\n" 01019 "</html>\r\n"; 01020 01021 //Compute the length of the response 01022 length = strlen(template) + 2 * strlen(uri) - 4; 01023 01024 //Format HTTP response header 01025 connection->response.statusCode = statusCode; 01026 connection->response.location = uri; 01027 connection->response.contentType = mimeGetType(".htm"); 01028 connection->response.chunkedEncoding = FALSE; 01029 connection->response.contentLength = length; 01030 01031 //Send the header to the client 01032 error = httpWriteHeader(connection); 01033 //Any error to report? 01034 if(error) 01035 return error; 01036 01037 //Format HTML response 01038 sprintf(connection->buffer, template, uri, uri); 01039 01040 //Send response body 01041 error = httpWriteStream(connection, connection->buffer, length); 01042 //Any error to report? 01043 if(error) 01044 return error; 01045 01046 //Properly close output stream 01047 error = httpCloseStream(connection); 01048 //Return status code 01049 return error; 01050 } 01051 01052 01053 /** 01054 * @brief Check whether the client's handshake is valid 01055 * @param[in] connection Structure representing an HTTP connection 01056 * @return TRUE if the WebSocket handshake is valid, else FALSE 01057 **/ 01058 01059 bool_t httpCheckWebSocketHandshake(HttpConnection *connection) 01060 { 01061 #if (HTTP_SERVER_WEB_SOCKET_SUPPORT == ENABLED) 01062 error_t error; 01063 size_t n; 01064 01065 //The request must contain an Upgrade header field whose value 01066 //must include the "websocket" keyword 01067 if(!connection->request.upgradeWebSocket) 01068 return FALSE; 01069 01070 //The request must contain a Connection header field whose value 01071 //must include the "Upgrade" token 01072 if(!connection->request.connectionUpgrade) 01073 return FALSE; 01074 01075 //Retrieve the length of the client's key 01076 n = strlen(connection->request.clientKey); 01077 01078 //The request must include a header field with the name Sec-WebSocket-Key 01079 if(n == 0) 01080 return FALSE; 01081 01082 //The value of the Sec-WebSocket-Key header field must be a 16-byte 01083 //value that has been Base64-encoded 01084 error = base64Decode(connection->request.clientKey, n, connection->buffer, &n); 01085 //Decoding failed? 01086 if(error) 01087 return FALSE; 01088 01089 //Check the length of the resulting value 01090 if(n != 16) 01091 return FALSE; 01092 01093 //The client's handshake is valid 01094 return TRUE; 01095 #else 01096 //WebSocket are not supported 01097 return FALSE; 01098 #endif 01099 } 01100 01101 01102 /** 01103 * @brief Upgrade an existing HTTP connection to a WebSocket 01104 * @param[in] connection Structure representing an HTTP connection 01105 * @return Handle referencing the new WebSocket 01106 **/ 01107 01108 WebSocket *httpUpgradeToWebSocket(HttpConnection *connection) 01109 { 01110 WebSocket *webSocket; 01111 01112 #if (HTTP_SERVER_WEB_SOCKET_SUPPORT == ENABLED) 01113 #if (HTTP_SERVER_TLS_SUPPORT == ENABLED) 01114 //Check whether a secure connection is being used 01115 if(connection->tlsContext != NULL) 01116 { 01117 //Upgrade the secure connection to a WebSocket 01118 webSocket = webSocketUpgradeSecureSocket(connection->socket, 01119 connection->tlsContext); 01120 } 01121 else 01122 #endif 01123 { 01124 //Upgrade the connection to a WebSocket 01125 webSocket = webSocketUpgradeSocket(connection->socket); 01126 } 01127 01128 //Succesful upgrade? 01129 if(webSocket != NULL) 01130 { 01131 error_t error; 01132 01133 //Copy client's key 01134 error = webSocketSetClientKey(webSocket, connection->request.clientKey); 01135 01136 //Check status code 01137 if(!error) 01138 { 01139 #if (HTTP_SERVER_TLS_SUPPORT == ENABLED) 01140 //Detach the SSL/TLS context from the HTTP connection 01141 connection->tlsContext = NULL; 01142 #endif 01143 //Detach the socket from the HTTP connection 01144 connection->socket = NULL; 01145 } 01146 else 01147 { 01148 //Clean up side effects 01149 webSocketClose(webSocket); 01150 webSocket = NULL; 01151 } 01152 } 01153 #else 01154 //WebSockets are not supported 01155 webSocket = NULL; 01156 #endif 01157 01158 //Return a handle to the freshly created WebSocket 01159 return webSocket; 01160 } 01161 01162 01163 #endif 01164
Generated on Tue Jul 12 2022 17:10:13 by
