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