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