Webserver+3d print

Dependents:   Nucleo

Committer:
Sergunb
Date:
Sat Feb 04 18:15:49 2017 +0000
Revision:
0:8918a71cdbe9
nothing else

Who changed what in which revision?

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