http_server.c
Go to the documentation of this file.
1 /**
2  * @file http_server.c
3  * @brief HTTP server (HyperText Transfer Protocol)
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2024 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneTCP Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @section Description
28  *
29  * Using the HyperText Transfer Protocol, the HTTP server delivers web pages
30  * to browsers as well as other data files to web-based applications. Refers
31  * to the following RFCs for complete details:
32  * - RFC 1945: Hypertext Transfer Protocol - HTTP/1.0
33  * - RFC 2616: Hypertext Transfer Protocol - HTTP/1.1
34  * - RFC 2617: HTTP Authentication: Basic and Digest Access Authentication
35  * - RFC 2818: HTTP Over TLS
36  *
37  * @author Oryx Embedded SARL (www.oryx-embedded.com)
38  * @version 2.4.4
39  **/
40 
41 //Switch to the appropriate trace level
42 #define TRACE_LEVEL HTTP_TRACE_LEVEL
43 
44 //Dependencies
45 #include "core/net.h"
46 #include "http/http_server.h"
47 #include "http/http_server_auth.h"
48 #include "http/http_server_misc.h"
49 #include "http/mime.h"
50 #include "http/ssi.h"
51 #include "debug.h"
52 
53 //Check TCP/IP stack configuration
54 #if (HTTP_SERVER_SUPPORT == ENABLED)
55 
56 
57 /**
58  * @brief Initialize settings with default values
59  * @param[out] settings Structure that contains HTTP server settings
60  **/
61 
63 {
64  uint_t i;
65 
66  //Initialize listener task parameters
70 
71  //Initialize connection task parameters
72  for(i = 0; i < HTTP_SERVER_MAX_CONNECTIONS; i++)
73  {
74  //Default task parameters
78  }
79 
80  //The HTTP server is not bound to any interface
81  settings->interface = NULL;
82 
83  //Listen to port 80
84  settings->port = HTTP_PORT;
85  //HTTP server IP address
86  settings->ipAddr = IP_ADDR_ANY;
87  //Maximum length of the pending connection queue
88  settings->backlog = HTTP_SERVER_BACKLOG;
89 
90  //Client connections
91  settings->maxConnections = 0;
92  settings->connections = NULL;
93 
94  //Specify the server's root directory
95  osStrcpy(settings->rootDirectory, "/");
96  //Set default home page
97  osStrcpy(settings->defaultDocument, "index.htm");
98 
99 #if (HTTP_SERVER_TLS_SUPPORT == ENABLED)
100  //TLS initialization callback function
101  settings->tlsInitCallback = NULL;
102 #endif
103 
104 #if (HTTP_SERVER_BASIC_AUTH_SUPPORT == ENABLED || HTTP_SERVER_DIGEST_AUTH_SUPPORT == ENABLED)
105  //Random data generation callback function
106  settings->randCallback = NULL;
107  //HTTP authentication callback function
108  settings->authCallback = NULL;
109 #endif
110 
111  //CGI callback function
112  settings->cgiCallback = NULL;
113  //HTTP request callback function
114  settings->requestCallback = NULL;
115  //URI not found callback function
116  settings->uriNotFoundCallback = NULL;
117 }
118 
119 
120 /**
121  * @brief HTTP server initialization
122  * @param[in] context Pointer to the HTTP server context
123  * @param[in] settings HTTP server specific settings
124  * @return Error code
125  **/
126 
128 {
129  error_t error;
130  uint_t i;
131  HttpConnection *connection;
132 
133  //Debug message
134  TRACE_INFO("Initializing HTTP server...\r\n");
135 
136  //Ensure the parameters are valid
137  if(context == NULL || settings == NULL)
139 
140  //Check settings
141  if(settings->connections == NULL || settings->maxConnections < 1 ||
143  {
145  }
146 
147  //Clear the HTTP server context
148  osMemset(context, 0, sizeof(HttpServerContext));
149 
150  //Initialize task parameters
151  context->taskParams = settings->listenerTask;
152  context->taskId = OS_INVALID_TASK_ID;
153 
154  //Save user settings
155  context->settings = *settings;
156  //Client connections
157  context->connections = settings->connections;
158 
159  //Create a semaphore to limit the number of simultaneous connections
160  if(!osCreateSemaphore(&context->semaphore, context->settings.maxConnections))
161  return ERROR_OUT_OF_RESOURCES;
162 
163  //Loop through client connections
164  for(i = 0; i < context->settings.maxConnections; i++)
165  {
166  //Point to the structure representing the client connection
167  connection = &context->connections[i];
168 
169  //Initialize the structure
170  osMemset(connection, 0, sizeof(HttpConnection));
171 
172  //Initialize task parameters
173  connection->taskParams = settings->connectionTask[i];
174  connection->taskId = OS_INVALID_TASK_ID;
175 
176  //Create an event object to manage connection lifetime
177  if(!osCreateEvent(&connection->startEvent))
178  return ERROR_OUT_OF_RESOURCES;
179  }
180 
181 #if (HTTP_SERVER_TLS_SUPPORT == ENABLED && TLS_TICKET_SUPPORT == ENABLED)
182  //Initialize ticket encryption context
183  error = tlsInitTicketContext(&context->tlsTicketContext);
184  //Any error to report?
185  if(error)
186  return error;
187 #endif
188 
189 #if (HTTP_SERVER_DIGEST_AUTH_SUPPORT == ENABLED)
190  //Create a mutex to prevent simultaneous access to the nonce cache
191  if(!osCreateMutex(&context->nonceCacheMutex))
192  return ERROR_OUT_OF_RESOURCES;
193 #endif
194 
195  //Open a TCP socket
197  //Failed to open socket?
198  if(context->socket == NULL)
199  return ERROR_OPEN_FAILED;
200 
201  //Set timeout for blocking functions
202  error = socketSetTimeout(context->socket, INFINITE_DELAY);
203  //Any error to report?
204  if(error)
205  return error;
206 
207  //Associate the socket with the relevant interface
208  error = socketBindToInterface(context->socket, settings->interface);
209  //Unable to bind the socket to the desired interface?
210  if(error)
211  return error;
212 
213  //Bind newly created socket to port 80
214  error = socketBind(context->socket, &settings->ipAddr, settings->port);
215  //Failed to bind socket to port 80?
216  if(error)
217  return error;
218 
219  //Place socket in listening state
220  error = socketListen(context->socket, settings->backlog);
221  //Any failure to report?
222  if(error)
223  return error;
224 
225  //Successful initialization
226  return NO_ERROR;
227 }
228 
229 
230 /**
231  * @brief Start HTTP server
232  * @param[in] context Pointer to the HTTP server context
233  * @return Error code
234  **/
235 
237 {
238  uint_t i;
239  HttpConnection *connection;
240 
241  //Make sure the HTTP server context is valid
242  if(context == NULL)
244 
245  //Debug message
246  TRACE_INFO("Starting HTTP server...\r\n");
247 
248  //Loop through client connections
249  for(i = 0; i < context->settings.maxConnections; i++)
250  {
251  //Point to the current session
252  connection = &context->connections[i];
253 
254  //Create a task
255  connection->taskId = osCreateTask("HTTP Connection", httpConnectionTask,
256  connection, &connection->taskParams);
257 
258  //Unable to create the task?
259  if(connection->taskId == OS_INVALID_TASK_ID)
260  return ERROR_OUT_OF_RESOURCES;
261  }
262 
263  //Create a task
264  context->taskId = osCreateTask("HTTP Listener", httpListenerTask,
265  context, &context->taskParams);
266 
267  //Unable to create the task?
268  if(context->taskId == OS_INVALID_TASK_ID)
269  return ERROR_OUT_OF_RESOURCES;
270 
271  //The HTTP server has successfully started
272  return NO_ERROR;
273 }
274 
275 
276 /**
277  * @brief HTTP server listener task
278  * @param[in] param Pointer to the HTTP server context
279  **/
280 
281 void httpListenerTask(void *param)
282 {
283  uint_t i;
284  uint_t counter;
285  uint16_t clientPort;
286  IpAddr clientIpAddr;
287  HttpServerContext *context;
288  HttpConnection *connection;
289  Socket *socket;
290 
291  //Task prologue
292  osEnterTask();
293 
294  //Retrieve the HTTP server context
295  context = (HttpServerContext *) param;
296 
297  //Process incoming connections to the server
298  for(counter = 1; ; counter++)
299  {
300  //Debug message
301  TRACE_INFO("Ready to accept a new connection...\r\n");
302 
303  //Limit the number of simultaneous connections to the HTTP server
304  osWaitForSemaphore(&context->semaphore, INFINITE_DELAY);
305 
306  //Loop through the connection table
307  for(i = 0; i < context->settings.maxConnections; i++)
308  {
309  //Point to the current connection
310  connection = &context->connections[i];
311 
312  //Ready to service the client request?
313  if(!connection->running)
314  {
315  //Accept an incoming connection
316  socket = socketAccept(context->socket, &clientIpAddr, &clientPort);
317 
318  //Make sure the socket handle is valid
319  if(socket != NULL)
320  {
321  //Just for sanity
322  (void) counter;
323 
324  //Debug message
325  TRACE_INFO("Connection #%u established with client %s port %" PRIu16 "...\r\n",
326  counter, ipAddrToString(&clientIpAddr, NULL), clientPort);
327 
328  //Reference to the HTTP server settings
329  connection->settings = &context->settings;
330  //Reference to the HTTP server context
331  connection->serverContext = context;
332  //Reference to the new socket
333  connection->socket = socket;
334 
335  //Set timeout for blocking functions
336  socketSetTimeout(connection->socket, HTTP_SERVER_TIMEOUT);
337 
338  //The client connection task is now running...
339  connection->running = TRUE;
340  //Service the current connection request
341  osSetEvent(&connection->startEvent);
342  }
343  else
344  {
345  //Just for sanity
346  osReleaseSemaphore(&context->semaphore);
347  }
348 
349  //We are done
350  break;
351  }
352  }
353  }
354 }
355 
356 
357 /**
358  * @brief Task that services requests from an active connection
359  * @param[in] param Structure representing an HTTP connection with a client
360  **/
361 
362 void httpConnectionTask(void *param)
363 {
364  error_t error;
365  uint_t counter;
366  HttpConnection *connection;
367 
368  //Task prologue
369  osEnterTask();
370 
371  //Point to the structure representing the HTTP connection
372  connection = (HttpConnection *) param;
373 
374  //Endless loop
375  while(1)
376  {
377  //Wait for an incoming connection attempt
378  osWaitForEvent(&connection->startEvent, INFINITE_DELAY);
379 
380  //Initialize status code
381  error = NO_ERROR;
382 
383 #if (HTTP_SERVER_TLS_SUPPORT == ENABLED)
384  //TLS-secured connection?
385  if(connection->settings->tlsInitCallback != NULL)
386  {
387  //Debug message
388  TRACE_INFO("Initializing TLS session...\r\n");
389 
390  //Start of exception handling block
391  do
392  {
393  //Allocate TLS context
394  connection->tlsContext = tlsInit();
395  //Initialization failed?
396  if(connection->tlsContext == NULL)
397  {
398  //Report an error
399  error = ERROR_OUT_OF_MEMORY;
400  //Exit immediately
401  break;
402  }
403 
404  //Select server operation mode
405  error = tlsSetConnectionEnd(connection->tlsContext,
407  //Any error to report?
408  if(error)
409  break;
410 
411  //Bind TLS to the relevant socket
412  error = tlsSetSocket(connection->tlsContext, connection->socket);
413  //Any error to report?
414  if(error)
415  break;
416 
417 #if (TLS_TICKET_SUPPORT == ENABLED)
418  //Enable session ticket mechanism
419  error = tlsEnableSessionTickets(connection->tlsContext, TRUE);
420  //Any error to report?
421  if(error)
422  break;
423 
424  //Register ticket encryption/decryption callbacks
425  error = tlsSetTicketCallbacks(connection->tlsContext, tlsEncryptTicket,
426  tlsDecryptTicket, &connection->serverContext->tlsTicketContext);
427  //Any error to report?
428  if(error)
429  break;
430 #endif
431  //Invoke user-defined callback, if any
432  if(connection->settings->tlsInitCallback != NULL)
433  {
434  //Perform TLS related initialization
435  error = connection->settings->tlsInitCallback(connection,
436  connection->tlsContext);
437  //Any error to report?
438  if(error)
439  break;
440  }
441 
442  //Establish a secure session
443  error = tlsConnect(connection->tlsContext);
444  //Any error to report?
445  if(error)
446  break;
447 
448  //End of exception handling block
449  } while(0);
450  }
451  else
452  {
453  //Do not use TLS
454  connection->tlsContext = NULL;
455  }
456 #endif
457 
458  //Check status code
459  if(!error)
460  {
461  //Process incoming requests
462  for(counter = 0; counter < HTTP_SERVER_MAX_REQUESTS; counter++)
463  {
464  //Debug message
465  TRACE_INFO("Waiting for request...\r\n");
466 
467  //Clear request header
468  osMemset(&connection->request, 0, sizeof(HttpRequest));
469  //Clear response header
470  osMemset(&connection->response, 0, sizeof(HttpResponse));
471 
472  //Read the HTTP request header and parse its contents
473  error = httpReadRequestHeader(connection);
474  //Any error to report?
475  if(error)
476  {
477  //Debug message
478  TRACE_INFO("No HTTP request received or parsing error...\r\n");
479  break;
480  }
481 
482 #if (HTTP_SERVER_BASIC_AUTH_SUPPORT == ENABLED || HTTP_SERVER_DIGEST_AUTH_SUPPORT == ENABLED)
483  //No Authorization header found?
484  if(!connection->request.auth.found)
485  {
486  //Invoke user-defined callback, if any
487  if(connection->settings->authCallback != NULL)
488  {
489  //Check whether the access to the specified URI is authorized
490  connection->status = connection->settings->authCallback(connection,
491  connection->request.auth.user, connection->request.uri);
492  }
493  else
494  {
495  //Access to the specified URI is allowed
496  connection->status = HTTP_ACCESS_ALLOWED;
497  }
498  }
499 
500  //Check access status
501  if(connection->status == HTTP_ACCESS_ALLOWED)
502  {
503  //Access to the specified URI is allowed
504  error = NO_ERROR;
505  }
506  else if(connection->status == HTTP_ACCESS_BASIC_AUTH_REQUIRED)
507  {
508  //Basic access authentication is required
509  connection->response.auth.mode = HTTP_AUTH_MODE_BASIC;
510  //Report an error
511  error = ERROR_AUTH_REQUIRED;
512  }
513  else if(connection->status == HTTP_ACCESS_DIGEST_AUTH_REQUIRED)
514  {
515  //Digest access authentication is required
516  connection->response.auth.mode = HTTP_AUTH_MODE_DIGEST;
517  //Report an error
518  error = ERROR_AUTH_REQUIRED;
519  }
520  else
521  {
522  //Access to the specified URI is denied
523  error = ERROR_NOT_FOUND;
524  }
525 #endif
526  //Debug message
527  TRACE_INFO("Sending HTTP response to the client...\r\n");
528 
529  //Check status code
530  if(!error)
531  {
532  //Default HTTP header fields
533  httpInitResponseHeader(connection);
534 
535  //Invoke user-defined callback, if any
536  if(connection->settings->requestCallback != NULL)
537  {
538  error = connection->settings->requestCallback(connection,
539  connection->request.uri);
540  }
541  else
542  {
543  //Keep processing...
544  error = ERROR_NOT_FOUND;
545  }
546 
547  //Check status code
548  if(error == ERROR_NOT_FOUND)
549  {
550 #if (HTTP_SERVER_SSI_SUPPORT == ENABLED)
551  //Use server-side scripting to dynamically generate HTML code?
552  if(httpCompExtension(connection->request.uri, ".stm") ||
553  httpCompExtension(connection->request.uri, ".shtm") ||
554  httpCompExtension(connection->request.uri, ".shtml"))
555  {
556  //SSI processing (Server Side Includes)
557  error = ssiExecuteScript(connection, connection->request.uri, 0);
558  }
559  else
560 #endif
561  {
562  //Set the maximum age for static resources
563  connection->response.maxAge = HTTP_SERVER_MAX_AGE;
564 
565  //Send the contents of the requested page
566  error = httpSendResponse(connection, connection->request.uri);
567  }
568  }
569 
570  //The requested resource is not available?
571  if(error == ERROR_NOT_FOUND)
572  {
573  //Default HTTP header fields
574  httpInitResponseHeader(connection);
575 
576  //Invoke user-defined callback, if any
577  if(connection->settings->uriNotFoundCallback != NULL)
578  {
579  error = connection->settings->uriNotFoundCallback(connection,
580  connection->request.uri);
581  }
582  }
583  }
584 
585  //Check status code
586  if(error)
587  {
588  //Default HTTP header fields
589  httpInitResponseHeader(connection);
590 
591  //Bad request?
592  if(error == ERROR_INVALID_REQUEST)
593  {
594  //Send an error 400 and close the connection immediately
595  httpSendErrorResponse(connection, 400,
596  "The request is badly formed");
597  }
598  //Authorization required?
599  else if(error == ERROR_AUTH_REQUIRED)
600  {
601  //Send an error 401 and keep the connection alive
602  error = httpSendErrorResponse(connection, 401,
603  "Authorization required");
604  }
605  //Page not found?
606  else if(error == ERROR_NOT_FOUND)
607  {
608  //Send an error 404 and keep the connection alive
609  error = httpSendErrorResponse(connection, 404,
610  "The requested page could not be found");
611  }
612  }
613 
614  //Internal error?
615  if(error)
616  {
617  //Close the connection immediately
618  break;
619  }
620 
621  //Check whether the connection is persistent or not
622  if(!connection->request.keepAlive || !connection->response.keepAlive)
623  {
624  //Close the connection immediately
625  break;
626  }
627  }
628  }
629 
630 #if (HTTP_SERVER_TLS_SUPPORT == ENABLED)
631  //Valid TLS context?
632  if(connection->tlsContext != NULL)
633  {
634  //Debug message
635  TRACE_INFO("Closing TLS session...\r\n");
636 
637  //Gracefully close TLS session
638  tlsShutdown(connection->tlsContext);
639  //Release context
640  tlsFree(connection->tlsContext);
641  }
642 #endif
643 
644  //Valid socket handle?
645  if(connection->socket != NULL)
646  {
647  //Debug message
648  TRACE_INFO("Graceful shutdown...\r\n");
649  //Graceful shutdown
650  socketShutdown(connection->socket, SOCKET_SD_BOTH);
651 
652  //Debug message
653  TRACE_INFO("Closing socket...\r\n");
654  //Close socket
655  socketClose(connection->socket);
656  }
657 
658  //Ready to serve the next connection request...
659  connection->running = FALSE;
660  //Release semaphore
661  osReleaseSemaphore(&connection->serverContext->semaphore);
662  }
663 }
664 
665 
666 /**
667  * @brief Send HTTP response header
668  * @param[in] connection Structure representing an HTTP connection
669  * @return Error code
670  **/
671 
673 {
674  error_t error;
675 
676 #if (NET_RTOS_SUPPORT == DISABLED)
677  //Flush buffer
678  connection->bufferPos = 0;
679  connection->bufferLen = 0;
680 #endif
681 
682  //Format HTTP response header
683  error = httpFormatResponseHeader(connection, connection->buffer);
684 
685  //Check status code
686  if(!error)
687  {
688  //Debug message
689  TRACE_DEBUG("HTTP response header:\r\n%s", connection->buffer);
690 
691  //Send HTTP response header to the client
692  error = httpSend(connection, connection->buffer,
693  osStrlen(connection->buffer), HTTP_FLAG_DELAY);
694  }
695 
696  //Return status code
697  return error;
698 }
699 
700 
701 /**
702  * @brief Read data from client request
703  * @param[in] connection Structure representing an HTTP connection
704  * @param[out] data Buffer where to store the incoming data
705  * @param[in] size Maximum number of bytes that can be received
706  * @param[out] received Number of bytes that have been received
707  * @param[in] flags Set of flags that influences the behavior of this function
708  * @return Error code
709  **/
710 
712  void *data, size_t size, size_t *received, uint_t flags)
713 {
714  error_t error;
715  size_t n;
716 
717  //No data has been read yet
718  *received = 0;
719 
720  //Chunked encoding transfer is used?
721  if(connection->request.chunkedEncoding)
722  {
723  //Point to the output buffer
724  char_t *p = data;
725 
726  //Read as much data as possible
727  while(*received < size)
728  {
729  //End of HTTP request body?
730  if(connection->request.lastChunk)
731  return ERROR_END_OF_STREAM;
732 
733  //Acquire a new chunk when the current chunk
734  //has been completely consumed
735  if(connection->request.byteCount == 0)
736  {
737  //The size of each chunk is sent right before the chunk itself
738  error = httpReadChunkSize(connection);
739  //Failed to decode the chunk-size field?
740  if(error)
741  return error;
742 
743  //Any chunk whose size is zero terminates the data transfer
744  if(!connection->request.byteCount)
745  {
746  //The user must be satisfied with data already on hand
747  return (*received > 0) ? NO_ERROR : ERROR_END_OF_STREAM;
748  }
749  }
750 
751  //Limit the number of bytes to read at a time
752  n = MIN(size - *received, connection->request.byteCount);
753 
754  //Read data
755  error = httpReceive(connection, p, n, &n, flags);
756  //Any error to report?
757  if(error)
758  return error;
759 
760  //Total number of data that have been read
761  *received += n;
762  //Number of bytes left to process in the current chunk
763  connection->request.byteCount -= n;
764 
765  //The HTTP_FLAG_BREAK_CHAR flag causes the function to stop reading
766  //data as soon as the specified break character is encountered
767  if((flags & HTTP_FLAG_BREAK_CHAR) != 0)
768  {
769  //Check whether a break character has been received
770  if(p[n - 1] == LSB(flags))
771  break;
772  }
773  //The HTTP_FLAG_WAIT_ALL flag causes the function to return
774  //only when the requested number of bytes have been read
775  else if((flags & HTTP_FLAG_WAIT_ALL) == 0)
776  {
777  break;
778  }
779 
780  //Advance data pointer
781  p += n;
782  }
783  }
784  //Default encoding?
785  else
786  {
787  //Return immediately if the end of the request body has been reached
788  if(!connection->request.byteCount)
789  return ERROR_END_OF_STREAM;
790 
791  //Limit the number of bytes to read
792  n = MIN(size, connection->request.byteCount);
793 
794  //Read data
795  error = httpReceive(connection, data, n, received, flags);
796  //Any error to report?
797  if(error)
798  return error;
799 
800  //Decrement the count of remaining bytes to read
801  connection->request.byteCount -= *received;
802  }
803 
804  //Successful read operation
805  return NO_ERROR;
806 }
807 
808 
809 /**
810  * @brief Write data to the client
811  * @param[in] connection Structure representing an HTTP connection
812  * @param[in] data Buffer containing the data to be transmitted
813  * @param[in] length Number of bytes to be transmitted
814  * @return Error code
815  **/
816 
818  const void *data, size_t length)
819 {
820  error_t error;
821  uint_t n;
822 
823  //Use chunked encoding transfer?
824  if(connection->response.chunkedEncoding)
825  {
826  //Any data to send?
827  if(length > 0)
828  {
829  char_t s[12];
830 
831  //The chunk-size field is a string of hex digits indicating the size
832  //of the chunk
833  n = osSprintf(s, "%" PRIXSIZE "\r\n", length);
834 
835  //Send the chunk-size field
836  error = httpSend(connection, s, n, HTTP_FLAG_DELAY);
837  //Failed to send data?
838  if(error)
839  return error;
840 
841  //Send the chunk-data
842  error = httpSend(connection, data, length, HTTP_FLAG_DELAY);
843  //Failed to send data?
844  if(error)
845  return error;
846 
847  //Terminate the chunk-data by CRLF
848  error = httpSend(connection, "\r\n", 2, HTTP_FLAG_DELAY);
849  }
850  else
851  {
852  //Any chunk whose size is zero may terminate the data
853  //transfer and must be discarded
854  error = NO_ERROR;
855  }
856  }
857  //Default encoding?
858  else
859  {
860  //The length of the body shall not exceed the value
861  //specified in the Content-Length field
862  length = MIN(length, connection->response.byteCount);
863 
864  //Send user data
865  error = httpSend(connection, data, length, HTTP_FLAG_DELAY);
866 
867  //Decrement the count of remaining bytes to be transferred
868  connection->response.byteCount -= length;
869  }
870 
871  //Return status code
872  return error;
873 }
874 
875 
876 /**
877  * @brief Close output stream
878  * @param[in] connection Structure representing an HTTP connection
879  * @return Error code
880  **/
881 
883 {
884  error_t error;
885 
886  //Use chunked encoding transfer?
887  if(connection->response.chunkedEncoding)
888  {
889  //The chunked encoding is ended by any chunk whose size is zero
890  error = httpSend(connection, "0\r\n\r\n", 5, HTTP_FLAG_NO_DELAY);
891  }
892  else
893  {
894  //Flush the send buffer
895  error = httpSend(connection, "", 0, HTTP_FLAG_NO_DELAY);
896  }
897 
898  //Return status code
899  return error;
900 }
901 
902 
903 /**
904  * @brief Send HTTP response
905  * @param[in] connection Structure representing an HTTP connection
906  * @param[in] uri NULL-terminated string containing the file to be sent in response
907  * @return Error code
908  **/
909 
911 {
912 #if (HTTP_SERVER_FS_SUPPORT == ENABLED)
913  error_t error;
914  size_t n;
915  uint32_t length;
916  FsFile *file;
917 
918  //Retrieve the full pathname
919  httpGetAbsolutePath(connection, uri, connection->buffer,
921 
922 #if (HTTP_SERVER_GZIP_TYPE_SUPPORT == ENABLED)
923  //Check whether gzip compression is supported by the client
924  if(connection->request.acceptGzipEncoding)
925  {
926  //Calculate the length of the pathname
927  n = osStrlen(connection->buffer);
928 
929  //Sanity check
930  if(n < (HTTP_SERVER_BUFFER_SIZE - 4))
931  {
932  //Append gzip extension
933  osStrcpy(connection->buffer + n, ".gz");
934  //Retrieve the size of the compressed resource, if any
935  error = fsGetFileSize(connection->buffer, &length);
936  }
937  else
938  {
939  //Report an error
940  error = ERROR_NOT_FOUND;
941  }
942 
943  //Check whether the gzip-compressed file exists
944  if(!error)
945  {
946  //Use gzip format
947  connection->response.gzipEncoding = TRUE;
948  }
949  else
950  {
951  //Strip the gzip extension
952  connection->buffer[n] = '\0';
953 
954  //Retrieve the size of the non-compressed resource
955  error = fsGetFileSize(connection->buffer, &length);
956  //The specified URI cannot be found?
957  if(error)
958  return ERROR_NOT_FOUND;
959  }
960  }
961  else
962 #endif
963  {
964  //Retrieve the size of the specified file
965  error = fsGetFileSize(connection->buffer, &length);
966  //The specified URI cannot be found?
967  if(error)
968  return ERROR_NOT_FOUND;
969  }
970 
971  //Open the file for reading
972  file = fsOpenFile(connection->buffer, FS_FILE_MODE_READ);
973  //Failed to open the file?
974  if(file == NULL)
975  return ERROR_NOT_FOUND;
976 #else
977  error_t error;
978  size_t length;
979  const uint8_t *data;
980 
981  //Retrieve the full pathname
982  httpGetAbsolutePath(connection, uri, connection->buffer,
984 
985 #if (HTTP_SERVER_GZIP_TYPE_SUPPORT == ENABLED)
986  //Check whether gzip compression is supported by the client
987  if(connection->request.acceptGzipEncoding)
988  {
989  size_t n;
990 
991  //Calculate the length of the pathname
992  n = osStrlen(connection->buffer);
993 
994  //Sanity check
995  if(n < (HTTP_SERVER_BUFFER_SIZE - 4))
996  {
997  //Append gzip extension
998  osStrcpy(connection->buffer + n, ".gz");
999  //Get the compressed resource data associated with the URI, if any
1000  error = resGetData(connection->buffer, &data, &length);
1001  }
1002  else
1003  {
1004  //Report an error
1005  error = ERROR_NOT_FOUND;
1006  }
1007 
1008  //Check whether the gzip-compressed resource exists
1009  if(!error)
1010  {
1011  //Use gzip format
1012  connection->response.gzipEncoding = TRUE;
1013  }
1014  else
1015  {
1016  //Strip the gzip extension
1017  connection->buffer[n] = '\0';
1018 
1019  //Get the non-compressed resource data associated with the URI
1020  error = resGetData(connection->buffer, &data, &length);
1021  //The specified URI cannot be found?
1022  if(error)
1023  return error;
1024  }
1025  }
1026  else
1027 #endif
1028  {
1029  //Get the resource data associated with the URI
1030  error = resGetData(connection->buffer, &data, &length);
1031  //The specified URI cannot be found?
1032  if(error)
1033  return error;
1034  }
1035 #endif
1036 
1037  //Format HTTP response header
1038  connection->response.statusCode = 200;
1039  connection->response.contentType = mimeGetType(uri);
1040  connection->response.chunkedEncoding = FALSE;
1041  connection->response.contentLength = length;
1042 
1043  //Send the header to the client
1044  error = httpWriteHeader(connection);
1045  //Any error to report?
1046  if(error)
1047  {
1048 #if (HTTP_SERVER_FS_SUPPORT == ENABLED)
1049  //Close the file
1050  fsCloseFile(file);
1051 #endif
1052  //Return status code
1053  return error;
1054  }
1055 
1056 #if (HTTP_SERVER_FS_SUPPORT == ENABLED)
1057  //Send response body
1058  while(length > 0)
1059  {
1060  //Limit the number of bytes to read at a time
1062 
1063  //Read data from the specified file
1064  error = fsReadFile(file, connection->buffer, n, &n);
1065  //End of input stream?
1066  if(error)
1067  break;
1068 
1069  //Send data to the client
1070  error = httpWriteStream(connection, connection->buffer, n);
1071  //Any error to report?
1072  if(error)
1073  break;
1074 
1075  //Decrement the count of remaining bytes to be transferred
1076  length -= n;
1077  }
1078 
1079  //Close the file
1080  fsCloseFile(file);
1081 
1082  //Successful file transfer?
1083  if(error == NO_ERROR || error == ERROR_END_OF_FILE)
1084  {
1085  if(length == 0)
1086  {
1087  //Properly close the output stream
1088  error = httpCloseStream(connection);
1089  }
1090  }
1091 #else
1092  //Send response body
1093  error = httpWriteStream(connection, data, length);
1094  //Any error to report?
1095  if(error)
1096  return error;
1097 
1098  //Properly close output stream
1099  error = httpCloseStream(connection);
1100 #endif
1101 
1102  //Return status code
1103  return error;
1104 }
1105 
1106 
1107 /**
1108  * @brief Send error response to the client
1109  * @param[in] connection Structure representing an HTTP connection
1110  * @param[in] statusCode HTTP status code
1111  * @param[in] message User message
1112  * @return Error code
1113  **/
1114 
1116  uint_t statusCode, const char_t *message)
1117 {
1118  error_t error;
1119  size_t length;
1120 
1121  //HTML response template
1122  static const char_t template[] =
1123  "<!doctype html>\r\n"
1124  "<html>\r\n"
1125  "<head><title>Error %03d</title></head>\r\n"
1126  "<body>\r\n"
1127  "<h2>Error %03d</h2>\r\n"
1128  "<p>%s</p>\r\n"
1129  "</body>\r\n"
1130  "</html>\r\n";
1131 
1132  //Compute the length of the response
1133  length = osStrlen(template) + osStrlen(message) - 4;
1134 
1135  //Check whether the HTTP request has a body
1136  if(osStrcasecmp(connection->request.method, "GET") != 0 &&
1137  osStrcasecmp(connection->request.method, "HEAD") != 0 &&
1138  osStrcasecmp(connection->request.method, "DELETE") != 0)
1139  {
1140  //Drop the HTTP request body and close the connection after sending
1141  //the HTTP response
1142  connection->response.keepAlive = FALSE;
1143  }
1144 
1145  //Format HTTP response header
1146  connection->response.statusCode = statusCode;
1147  connection->response.contentType = mimeGetType(".htm");
1148  connection->response.chunkedEncoding = FALSE;
1149  connection->response.contentLength = length;
1150 
1151  //Send the header to the client
1152  error = httpWriteHeader(connection);
1153  //Any error to report?
1154  if(error)
1155  return error;
1156 
1157  //Format HTML response
1158  osSprintf(connection->buffer, template, statusCode, statusCode, message);
1159 
1160  //Send response body
1161  error = httpWriteStream(connection, connection->buffer, length);
1162  //Any error to report?
1163  if(error)
1164  return error;
1165 
1166  //Properly close output stream
1167  error = httpCloseStream(connection);
1168  //Return status code
1169  return error;
1170 }
1171 
1172 
1173 /**
1174  * @brief Send redirect response to the client
1175  * @param[in] connection Structure representing an HTTP connection
1176  * @param[in] statusCode HTTP status code (301 for permanent redirects)
1177  * @param[in] uri NULL-terminated string containing the redirect URI
1178  * @return Error code
1179  **/
1180 
1182  uint_t statusCode, const char_t *uri)
1183 {
1184  error_t error;
1185  size_t length;
1186 
1187  //HTML response template
1188  static const char_t template[] =
1189  "<!doctype html>\r\n"
1190  "<html>\r\n"
1191  "<head><title>Moved</title></head>\r\n"
1192  "<body>\r\n"
1193  "<h2>Moved</h2>\r\n"
1194  "<p>This page has moved to <a href=\"%s\">%s</a>.</p>"
1195  "</body>\r\n"
1196  "</html>\r\n";
1197 
1198  //Compute the length of the response
1199  length = osStrlen(template) + 2 * osStrlen(uri) - 4;
1200 
1201  //Check whether the HTTP request has a body
1202  if(osStrcasecmp(connection->request.method, "GET") != 0 &&
1203  osStrcasecmp(connection->request.method, "HEAD") != 0 &&
1204  osStrcasecmp(connection->request.method, "DELETE") != 0)
1205  {
1206  //Drop the HTTP request body and close the connection after sending
1207  //the HTTP response
1208  connection->response.keepAlive = FALSE;
1209  }
1210 
1211  //Format HTTP response header
1212  connection->response.statusCode = statusCode;
1213  connection->response.location = uri;
1214  connection->response.contentType = mimeGetType(".htm");
1215  connection->response.chunkedEncoding = FALSE;
1216  connection->response.contentLength = length;
1217 
1218  //Send the header to the client
1219  error = httpWriteHeader(connection);
1220  //Any error to report?
1221  if(error)
1222  return error;
1223 
1224  //Format HTML response
1225  osSprintf(connection->buffer, template, uri, uri);
1226 
1227  //Send response body
1228  error = httpWriteStream(connection, connection->buffer, length);
1229  //Any error to report?
1230  if(error)
1231  return error;
1232 
1233  //Properly close output stream
1234  error = httpCloseStream(connection);
1235  //Return status code
1236  return error;
1237 }
1238 
1239 
1240 /**
1241  * @brief Check whether the client's handshake is valid
1242  * @param[in] connection Structure representing an HTTP connection
1243  * @return TRUE if the WebSocket handshake is valid, else FALSE
1244  **/
1245 
1247 {
1248 #if (HTTP_SERVER_WEB_SOCKET_SUPPORT == ENABLED)
1249  error_t error;
1250  size_t n;
1251 
1252  //The request must contain an Upgrade header field whose value
1253  //must include the "websocket" keyword
1254  if(!connection->request.upgradeWebSocket)
1255  return FALSE;
1256 
1257  //The request must contain a Connection header field whose value
1258  //must include the "Upgrade" token
1259  if(!connection->request.connectionUpgrade)
1260  return FALSE;
1261 
1262  //Retrieve the length of the client's key
1263  n = osStrlen(connection->request.clientKey);
1264 
1265  //The request must include a header field with the name Sec-WebSocket-Key
1266  if(n == 0)
1267  return FALSE;
1268 
1269  //The value of the Sec-WebSocket-Key header field must be a 16-byte
1270  //value that has been Base64-encoded
1271  error = base64Decode(connection->request.clientKey, n, connection->buffer, &n);
1272  //Decoding failed?
1273  if(error)
1274  return FALSE;
1275 
1276  //Check the length of the resulting value
1277  if(n != 16)
1278  return FALSE;
1279 
1280  //The client's handshake is valid
1281  return TRUE;
1282 #else
1283  //WebSocket are not supported
1284  return FALSE;
1285 #endif
1286 }
1287 
1288 
1289 /**
1290  * @brief Upgrade an existing HTTP connection to a WebSocket
1291  * @param[in] connection Structure representing an HTTP connection
1292  * @return Handle referencing the new WebSocket
1293  **/
1294 
1296 {
1297  WebSocket *webSocket;
1298 
1299 #if (HTTP_SERVER_WEB_SOCKET_SUPPORT == ENABLED)
1300 #if (HTTP_SERVER_TLS_SUPPORT == ENABLED)
1301  //Check whether a secure connection is being used
1302  if(connection->tlsContext != NULL)
1303  {
1304  //Upgrade the secure connection to a WebSocket
1305  webSocket = webSocketUpgradeSecureSocket(connection->socket,
1306  connection->tlsContext);
1307  }
1308  else
1309 #endif
1310  {
1311  //Upgrade the connection to a WebSocket
1312  webSocket = webSocketUpgradeSocket(connection->socket);
1313  }
1314 
1315  //Succesful upgrade?
1316  if(webSocket != NULL)
1317  {
1318  error_t error;
1319 
1320  //Copy client's key
1321  error = webSocketSetClientKey(webSocket, connection->request.clientKey);
1322 
1323  //Check status code
1324  if(!error)
1325  {
1326 #if (HTTP_SERVER_TLS_SUPPORT == ENABLED)
1327  //Detach the TLS context from the HTTP connection
1328  connection->tlsContext = NULL;
1329 #endif
1330  //Detach the socket from the HTTP connection
1331  connection->socket = NULL;
1332  }
1333  else
1334  {
1335  //Clean up side effects
1336  webSocketClose(webSocket);
1337  webSocket = NULL;
1338  }
1339  }
1340 #else
1341  //WebSockets are not supported
1342  webSocket = NULL;
1343 #endif
1344 
1345  //Return a handle to the freshly created WebSocket
1346  return webSocket;
1347 }
1348 
1349 
1350 #endif
TlsContext * tlsInit(void)
TLS context initialization.
Definition: tls.c:65
void httpListenerTask(void *param)
HTTP server listener task.
Definition: http_server.c:281
OsTaskId osCreateTask(const char_t *name, OsTaskCode taskCode, void *arg, const OsTaskParameters *params)
Create a task.
error_t socketBind(Socket *socket, const IpAddr *localIpAddr, uint16_t localPort)
Associate a local address with a socket.
Definition: socket.c:1316
error_t tlsInitTicketContext(TlsTicketContext *ticketContext)
Initialize ticket encryption context.
Definition: tls_ticket.c:49
error_t tlsSetConnectionEnd(TlsContext *context, TlsConnectionEnd entity)
Set operation mode (client or server)
Definition: tls.c:349
error_t httpFormatResponseHeader(HttpConnection *connection, char_t *buffer)
Format HTTP response header.
int bool_t
Definition: compiler_port.h:53
@ ERROR_NOT_FOUND
Definition: error.h:147
bool_t osCreateMutex(OsMutex *mutex)
Create a mutex object.
#define HTTP_SERVER_BACKLOG
Definition: http_server.h:160
error_t httpWriteHeader(HttpConnection *connection)
Send HTTP response header.
Definition: http_server.c:672
error_t tlsDecryptTicket(TlsContext *context, const uint8_t *ciphertext, size_t ciphertextLen, uint8_t *plaintext, size_t *plaintextLen, void *param)
Session ticket decryption.
Definition: tls_ticket.c:221
HTTP server (HyperText Transfer Protocol)
IP network address.
Definition: ip.h:90
error_t fsGetFileSize(const char_t *path, uint32_t *size)
Retrieve the size of the specified file.
OsTaskParameters connectionTask[HTTP_SERVER_MAX_CONNECTIONS]
Connection task parameters.
Definition: http_server.h:549
HttpRandCallback randCallback
Random data generation callback function.
Definition: http_server.h:563
void osReleaseSemaphore(OsSemaphore *semaphore)
Release the specified semaphore object.
uint8_t p
Definition: ndp.h:300
#define HTTP_SERVER_TIMEOUT
Definition: http_server.h:145
bool_t httpCheckWebSocketHandshake(HttpConnection *connection)
Check whether the client's handshake is valid.
Definition: http_server.c:1246
uint8_t message[]
Definition: chap.h:154
#define TRUE
Definition: os_port.h:50
#define PRIXSIZE
uint8_t data[]
Definition: ethernet.h:222
#define OS_INVALID_TASK_ID
#define HttpServerContext
Definition: http_server.h:328
void socketClose(Socket *socket)
Close an existing socket.
Definition: socket.c:2062
@ ERROR_OUT_OF_RESOURCES
Definition: error.h:64
char_t * ipAddrToString(const IpAddr *ipAddr, char_t *str)
Convert a binary IP address to a string representation.
Definition: ip.c:805
HttpRequestCallback requestCallback
HTTP request callback function.
Definition: http_server.h:567
@ ERROR_OUT_OF_MEMORY
Definition: error.h:63
HttpConnection * connections
Client connections.
Definition: http_server.h:555
@ HTTP_AUTH_MODE_BASIC
Definition: http_common.h:74
error_t ssiExecuteScript(HttpConnection *connection, const char_t *uri, uint_t level)
Execute SSI script.
Definition: ssi.c:67
@ ERROR_AUTH_REQUIRED
Definition: error.h:150
#define osStrlen(s)
Definition: os_port.h:165
error_t httpServerStart(HttpServerContext *context)
Start HTTP server.
Definition: http_server.c:236
@ ERROR_END_OF_STREAM
Definition: error.h:210
@ HTTP_ACCESS_ALLOWED
Definition: http_server.h:347
@ SOCKET_TYPE_STREAM
Definition: socket.h:92
bool_t osWaitForSemaphore(OsSemaphore *semaphore, systime_t timeout)
Wait for the specified semaphore to be available.
error_t httpWriteStream(HttpConnection *connection, const void *data, size_t length)
Write data to the client.
Definition: http_server.c:817
error_t httpSendErrorResponse(HttpConnection *connection, uint_t statusCode, const char_t *message)
Send error response to the client.
Definition: http_server.c:1115
#define HTTP_SERVER_MAX_REQUESTS
Definition: http_server.h:167
error_t fsReadFile(FsFile *file, void *data, size_t size, size_t *length)
Read data from the specified file.
HTTP response.
Definition: http_server.h:519
bool_t osCreateSemaphore(OsSemaphore *semaphore, uint_t count)
Create a semaphore object.
@ ERROR_OPEN_FAILED
Definition: error.h:75
const IpAddr IP_ADDR_ANY
Definition: ip.c:53
error_t httpServerInit(HttpServerContext *context, const HttpServerSettings *settings)
HTTP server initialization.
Definition: http_server.c:127
#define HTTP_SERVER_PRIORITY
Definition: http_server.h:133
error_t base64Decode(const char_t *input, size_t inputLen, void *output, size_t *outputLen)
Base64 decoding algorithm.
Definition: base64.c:258
error_t tlsShutdown(TlsContext *context)
Gracefully close TLS session.
Definition: tls.c:2307
#define FALSE
Definition: os_port.h:46
TlsInitCallback tlsInitCallback
TLS initialization callback function.
Definition: http_server.h:560
@ ERROR_INVALID_PARAMETER
Invalid parameter.
Definition: error.h:47
#define tlsSetSocket(context, socket)
Definition: tls.h:927
@ HTTP_FLAG_NO_DELAY
Definition: http_common.h:100
@ HTTP_FLAG_BREAK_CHAR
Definition: http_common.h:98
@ HTTP_ACCESS_DIGEST_AUTH_REQUIRED
Definition: http_server.h:349
error_t
Error codes.
Definition: error.h:43
#define osSprintf(dest,...)
Definition: os_port.h:231
#define HttpConnection
Definition: http_server.h:332
@ TLS_CONNECTION_END_SERVER
Definition: tls.h:969
error_t webSocketSetClientKey(WebSocket *webSocket, const char_t *clientKey)
Set client's key.
Definition: web_socket.c:677
error_t tlsSetTicketCallbacks(TlsContext *context, TlsTicketEncryptCallback ticketEncryptCallback, TlsTicketDecryptCallback ticketDecryptCallback, void *param)
Set ticket encryption/decryption callbacks.
Definition: tls.c:1517
int_t socket(int_t family, int_t type, int_t protocol)
Create a socket that is bound to a specific transport service provider.
Definition: bsd_socket.c:65
void fsCloseFile(FsFile *file)
Close a file.
error_t httpReceive(HttpConnection *connection, void *data, size_t size, size_t *received, uint_t flags)
Receive data from the client.
error_t httpReadStream(HttpConnection *connection, void *data, size_t size, size_t *received, uint_t flags)
Read data from client request.
Definition: http_server.c:711
const char_t * mimeGetType(const char_t *filename)
Get the MIME type from a given extension.
Definition: mime.c:113
HTTP server (miscellaneous functions)
char_t defaultDocument[HTTP_SERVER_DEFAULT_DOC_MAX_LEN+1]
Default home page.
Definition: http_server.h:557
FsFile * fsOpenFile(const char_t *path, uint_t mode)
Open the specified file for reading or writing.
@ ERROR_END_OF_FILE
Definition: error.h:159
#define osStrcasecmp(s1, s2)
Definition: os_port.h:183
const OsTaskParameters OS_TASK_DEFAULT_PARAMS
#define HTTP_SERVER_MAX_CONNECTIONS
Definition: http_server.h:138
HTTP server settings.
Definition: http_server.h:547
uint16_t port
HTTP server port number.
Definition: http_server.h:551
error_t socketShutdown(Socket *socket, uint_t how)
Disable reception, transmission, or both.
Definition: socket.c:2020
error_t tlsEnableSessionTickets(TlsContext *context, bool_t enabled)
Enable session ticket mechanism.
Definition: tls.c:1437
#define TRACE_INFO(...)
Definition: debug.h:95
uint8_t length
Definition: tcp.h:368
WebSocket * httpUpgradeToWebSocket(HttpConnection *connection)
Upgrade an existing HTTP connection to a WebSocket.
Definition: http_server.c:1295
#define LSB(x)
Definition: os_port.h:55
Socket * socketOpen(uint_t type, uint_t protocol)
Create a socket (UDP or TCP)
Definition: socket.c:125
error_t resGetData(const char_t *path, const uint8_t **data, size_t *length)
error_t httpSend(HttpConnection *connection, const void *data, size_t length, uint_t flags)
Send data to the client.
#define MIN(a, b)
Definition: os_port.h:63
#define WebSocket
Definition: web_socket.h:177
#define osEnterTask()
OsTaskParameters listenerTask
Listener task parameters.
Definition: http_server.h:548
#define socketBindToInterface
Definition: net_legacy.h:193
@ HTTP_FLAG_DELAY
Definition: http_common.h:101
IpAddr ipAddr
HTTP server IP address.
Definition: http_server.h:552
uint_t backlog
Maximum length of the pending connection queue.
Definition: http_server.h:553
Socket * socketAccept(Socket *socket, IpAddr *clientIpAddr, uint16_t *clientPort)
Permit an incoming connection attempt on a socket.
Definition: socket.c:1451
HttpCgiCallback cgiCallback
CGI callback function.
Definition: http_server.h:566
WebSocket * webSocketUpgradeSocket(Socket *socket)
Upgrade a socket to a WebSocket.
Definition: web_socket.c:155
uint8_t flags
Definition: tcp.h:351
#define TRACE_DEBUG(...)
Definition: debug.h:107
HTTP authentication.
char char_t
Definition: compiler_port.h:48
#define HTTP_PORT
Definition: http_common.h:38
HTTP request.
Definition: http_server.h:481
WebSocket * webSocketUpgradeSecureSocket(Socket *socket, TlsContext *tlsContext)
Upgrade a secure socket to a secure WebSocket.
Definition: web_socket.c:194
uint8_t n
bool_t osWaitForEvent(OsEvent *event, systime_t timeout)
Wait until the specified event is in the signaled state.
void httpServerGetDefaultSettings(HttpServerSettings *settings)
Initialize settings with default values.
Definition: http_server.c:62
@ HTTP_AUTH_MODE_DIGEST
Definition: http_common.h:75
HttpAuthCallback authCallback
HTTP authentication callback function.
Definition: http_server.h:564
void httpGetAbsolutePath(HttpConnection *connection, const char_t *relative, char_t *absolute, size_t maxLen)
Retrieve the full pathname to the specified resource.
void webSocketClose(WebSocket *webSocket)
Close a WebSocket connection.
Definition: web_socket.c:1591
error_t tlsEncryptTicket(TlsContext *context, const uint8_t *plaintext, size_t plaintextLen, uint8_t *ciphertext, size_t *ciphertextLen, void *param)
Session ticket encryption.
Definition: tls_ticket.c:81
uint8_t file[128]
Definition: dhcp_common.h:223
#define Socket
Definition: socket.h:36
error_t httpSendResponse(HttpConnection *connection, const char_t *uri)
Send HTTP response.
Definition: http_server.c:910
uint_t maxConnections
Maximum number of client connections.
Definition: http_server.h:554
bool_t osCreateEvent(OsEvent *event)
Create an event object.
NetInterface * interface
Underlying network interface.
Definition: http_server.h:550
bool_t httpCompExtension(const char_t *filename, const char_t *extension)
Compare filename extension.
@ HTTP_FLAG_WAIT_ALL
Definition: http_common.h:97
error_t httpReadRequestHeader(HttpConnection *connection)
Read HTTP request header and parse its contents.
error_t httpCloseStream(HttpConnection *connection)
Close output stream.
Definition: http_server.c:882
uint8_t s
Definition: igmp_common.h:234
#define HTTP_SERVER_BUFFER_SIZE
Definition: http_server.h:174
void osSetEvent(OsEvent *event)
Set the specified event object to the signaled state.
void tlsFree(TlsContext *context)
Release TLS context.
Definition: tls.c:2469
@ FS_FILE_MODE_READ
Definition: fs_port.h:72
error_t httpSendRedirectResponse(HttpConnection *connection, uint_t statusCode, const char_t *uri)
Send redirect response to the client.
Definition: http_server.c:1181
MIME (Multipurpose Internet Mail Extensions)
error_t httpReadChunkSize(HttpConnection *connection)
Read chunk-size field from the input stream.
unsigned int uint_t
Definition: compiler_port.h:50
#define osMemset(p, value, length)
Definition: os_port.h:135
TCP/IP stack core.
#define HTTP_SERVER_STACK_SIZE
Definition: http_server.h:126
@ SOCKET_SD_BOTH
Definition: socket.h:161
#define osStrcpy(s1, s2)
Definition: os_port.h:207
@ SOCKET_IP_PROTO_TCP
Definition: socket.h:107
error_t socketSetTimeout(Socket *socket, systime_t timeout)
Set timeout value for blocking operations.
Definition: socket.c:148
#define HTTP_SERVER_MAX_AGE
Definition: http_server.h:244
SSI (Server Side Includes)
error_t tlsConnect(TlsContext *context)
Initiate the TLS handshake.
Definition: tls.c:1763
@ ERROR_INVALID_REQUEST
Definition: error.h:65
void httpConnectionTask(void *param)
Task that services requests from an active connection.
Definition: http_server.c:362
@ HTTP_ACCESS_BASIC_AUTH_REQUIRED
Definition: http_server.h:348
char_t rootDirectory[HTTP_SERVER_ROOT_DIR_MAX_LEN+1]
Web root directory.
Definition: http_server.h:556
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.
#define INFINITE_DELAY
Definition: os_port.h:75
void httpInitResponseHeader(HttpConnection *connection)
Initialize response header.
void FsFile
File descriptor.
Definition: fs_port_fatfs.h:60
HttpUriNotFoundCallback uriNotFoundCallback
URI not found callback function.
Definition: http_server.h:568
error_t socketListen(Socket *socket, uint_t backlog)
Place a socket in the listening state.
Definition: socket.c:1413