예제 #1
0
void httpConnectionTask(void *param)
{
   error_t error;
   uint_t counter;
   HttpConnection *connection;

   //Point to the structure representing the HTTP connection
   connection = (HttpConnection *) param;

   //Endless loop
   while(1)
   {
      //Wait for an incoming connection attempt
      osWaitForEvent(&connection->startEvent, INFINITE_DELAY);

      //Initialize status code
      error = NO_ERROR;

#if (HTTP_SERVER_TLS_SUPPORT == ENABLED)
      //Use SSL/TLS to secure the connection?
      if(connection->settings->useTls)
      {
         //Debug message
         TRACE_INFO("Initializing SSL/TLS session...\r\n");

         //Start of exception handling block
         do
         {
            //Allocate SSL/TLS context
            connection->tlsContext = tlsInit();
            //Initialization failed?
            if(connection->tlsContext == NULL)
            {
               //Report an error
               error = ERROR_OUT_OF_MEMORY;
               //Exit immediately
               break;
            }

            //Select server operation mode
            error = tlsSetConnectionEnd(connection->tlsContext, TLS_CONNECTION_END_SERVER);
            //Any error to report?
            if(error) break;

            //Bind TLS to the relevant socket
            error = tlsSetSocket(connection->tlsContext, connection->socket);
            //Any error to report?
            if(error) break;

            //Invoke user-defined callback, if any
            if(connection->settings->tlsInitCallback != NULL)
            {
               //Perform SSL/TLS related initialization
               error = connection->settings->tlsInitCallback(connection, connection->tlsContext);
               //Any error to report?
               if(error) break;
            }

            //Establish a secure session
            error = tlsConnect(connection->tlsContext);
            //Any error to report?
            if(error) break;

            //End of exception handling block
         } while(0);
      }
      else
      {
         //Do not use SSL/TLS
         connection->tlsContext = NULL;
      }
#endif

      //Check status code
      if(!error)
      {
         //Process incoming requests
         for(counter = 0; counter < HTTP_SERVER_MAX_REQUESTS; counter++)
         {
            //Debug message
            TRACE_INFO("Waiting for request...\r\n");

            //Clear request header
            memset(&connection->request, 0, sizeof(HttpRequest));
            //Clear response header
            memset(&connection->response, 0, sizeof(HttpResponse));

            //Read the HTTP request header and parse its contents
            error = httpReadHeader(connection);
            //Any error to report?
            if(error)
            {
               //Debug message
               TRACE_INFO("No HTTP request received or parsing error...\r\n");
               break;
            }

#if (HTTP_SERVER_BASIC_AUTH_SUPPORT == ENABLED || HTTP_SERVER_DIGEST_AUTH_SUPPORT == ENABLED)
            //No Authorization header found?
            if(!connection->request.auth.found)
            {
               //Invoke user-defined callback, if any
               if(connection->settings->authCallback != NULL)
               {
                  //Check whether the access to the specified URI is authorized
                  connection->status = connection->settings->authCallback(connection,
                     connection->request.auth.user, connection->request.uri);
               }
               else
               {
                  //Access to the specified URI is allowed
                  connection->status = HTTP_ACCESS_ALLOWED;
               }
            }

            //Check access status
            if(connection->status == HTTP_ACCESS_ALLOWED)
            {
               //Access to the specified URI is allowed
               error = NO_ERROR;
            }
            else if(connection->status == HTTP_ACCESS_BASIC_AUTH_REQUIRED)
            {
               //Basic access authentication is required
               connection->response.auth.mode = HTTP_AUTH_MODE_BASIC;
               //Report an error
               error = ERROR_AUTH_REQUIRED;
            }
            else if(connection->status == HTTP_ACCESS_DIGEST_AUTH_REQUIRED)
            {
               //Digest access authentication is required
               connection->response.auth.mode = HTTP_AUTH_MODE_DIGEST;
               //Report an error
               error = ERROR_AUTH_REQUIRED;
            }
            else
            {
               //Access to the specified URI is denied
               error = ERROR_NOT_FOUND;
            }
#endif

            //Debug message
            TRACE_INFO("Sending HTTP response to the client...\r\n");

            //Check status code
            if(!error)
            {
               //Default HTTP header fields
               connection->response.version = connection->request.version;
               connection->response.noCache = FALSE;

#if (HTTP_SERVER_PERSISTENT_CONN_SUPPORT == ENABLED)
               //Persistent connections are accepted
               connection->response.keepAlive = connection->request.keepAlive;
#else
               //Connections are not persistent by default
               connection->response.keepAlive = FALSE;
#endif

#if (HTTP_SERVER_SSI_SUPPORT == ENABLED)
               //Use server-side scripting to dynamically generate HTML code?
               if(httpCompExtension(connection->request.uri, ".stm") ||
                  httpCompExtension(connection->request.uri, ".shtm") ||
                  httpCompExtension(connection->request.uri, ".shtml"))
               {
                  //SSI processing (Server Side Includes)
                  error = ssiExecuteScript(connection, connection->request.uri, 0);
               }
               else
#endif
               {
                  //Send the contents of the requested page
                  error = httpSendResponse(connection, connection->request.uri);
               }

               //The requested resource is not available?
               if(error == ERROR_NOT_FOUND)
               {
                  //Default HTTP header fields
                  connection->response.version = connection->request.version;
                  connection->response.statusCode = 200;
                  connection->response.keepAlive = connection->request.keepAlive;
                  connection->response.noCache = FALSE;
                  connection->response.location = NULL;
                  connection->response.contentType = mimeGetType(connection->request.uri);
                  connection->response.chunkedEncoding = TRUE;

                  //Invoke user-defined callback, if any
                  if(connection->settings->uriNotFoundCallback != NULL)
                  {
                     error = connection->settings->uriNotFoundCallback(connection,
                        connection->request.uri);
                  }
               }
            }

            //Bad request?
            if(error == ERROR_INVALID_REQUEST)
            {
               //Send an error 400 and close the connection immediately
               httpSendErrorResponse(connection, 400,
                  "The request is badly formed");
            }
            //Authorization required?
            else if(error == ERROR_AUTH_REQUIRED)
            {
               //Send an error 401 and keep the connection alive
               error = httpSendErrorResponse(connection, 401,
                  "Authorization required");
            }
            //Page not found?
            else if(error == ERROR_NOT_FOUND)
            {
               //Send an error 404 and keep the connection alive
               error = httpSendErrorResponse(connection, 404,
                  "The requested page could not be found");
            }

            //Internal error?
            if(error)
            {
               //Close the connection immediately
               break;
            }

            //Check whether the connection is persistent or not
            if(!connection->request.keepAlive || !connection->response.keepAlive)
            {
               //Close the connection immediately
               break;
            }
         }
      }

#if (HTTP_SERVER_TLS_SUPPORT == ENABLED)
      //Valid SSL/TLS context?
      if(connection->tlsContext != NULL)
      {
         //Debug message
         TRACE_INFO("Closing SSL/TLS session...\r\n");

         //Gracefully close SSL/TLS session
         tlsShutdown(connection->tlsContext);
         //Release context
         tlsFree(connection->tlsContext);
      }
#endif

      //Debug message
      TRACE_INFO("Graceful shutdown...\r\n");
      //Graceful shutdown
      socketShutdown(connection->socket, SOCKET_SD_BOTH);

      //Debug message
      TRACE_INFO("Closing socket...\r\n");
      //Close socket
      socketClose(connection->socket);

      //Ready to serve the next connection request...
      connection->running = FALSE;
      //Release semaphore
      osReleaseSemaphore(&connection->serverContext->semaphore);
   }
}
예제 #2
0
error_t ssiProcessIncludeCommand(HttpConnection *connection,
   const char_t *tag, size_t length, const char_t *uri, uint_t level)
{
   error_t error;
   char_t *separator;
   char_t *attribute;
   char_t *value;
   char_t *path;
   char_t *p;

   //Discard invalid SSI directives
   if(length < 7 || length >= HTTP_SERVER_BUFFER_SIZE)
      return ERROR_INVALID_TAG;

   //Skip the SSI include command (7 bytes)
   memcpy(connection->buffer, tag + 7, length - 7);
   //Ensure the resulting string is NULL-terminated
   connection->buffer[length - 7] = '\0';

   //Check whether a separator is present
   separator = strchr(connection->buffer, '=');
   //Separator not found?
   if(!separator)
      return ERROR_INVALID_TAG;

   //Split the tag
   *separator = '\0';

   //Get attribute name and value
   attribute = strTrimWhitespace(connection->buffer);
   value = strTrimWhitespace(separator + 1);

   //Remove leading simple or double quote
   if(value[0] == '\'' || value[0] == '\"')
      value++;

   //Get the length of the attribute value
   length = strlen(value);

   //Remove trailing simple or double quote
   if(length > 0)
   {
      if(value[length - 1] == '\'' || value[length - 1] == '\"')
         value[length - 1] = '\0';
   }

   //Check the length of the filename
   if(strlen(value) > HTTP_SERVER_URI_MAX_LEN)
      return ERROR_INVALID_TAG;

   //The file parameter defines the included file as relative to the document path
   if(!strcasecmp(attribute, "file"))
   {
      //Allocate a buffer to hold the path to the file to be included
      path = osAllocMem(strlen(uri) + strlen(value) + 1);
      //Failed to allocate memory?
      if(!path) return ERROR_OUT_OF_MEMORY;

      //Copy the path identifying the script file being processed
      strcpy(path, uri);
      //Search for the last slash character
      p = strrchr(path, '/');

      //Remove the filename from the path if applicable
      if(p)
         strcpy(p + 1, value);
      else
         strcpy(path, value);
   }
   //The virtual parameter defines the included file as relative to the document root
   else if(!strcasecmp(attribute, "virtual"))
   {
      //Copy the absolute path
      path = strDuplicate(value);
      //Failed to duplicate the string?
      if(!path) return ERROR_OUT_OF_MEMORY;
   }
   //Unknown parameter...
   else
   {
      //Report an error
      return ERROR_INVALID_TAG;
   }

   //Use server-side scripting to dynamically generate HTML code?
   if(httpCompExtension(value, ".stm") ||
      httpCompExtension(value, ".shtm") ||
      httpCompExtension(value, ".shtml"))
   {
      //SSI processing (Server Side Includes)
      error = ssiExecuteScript(connection, path, level + 1);
   }
   else
   {
#if (HTTP_SERVER_FS_SUPPORT == ENABLED)
      FsFile *file;

      //Retrieve the full pathname
      httpGetAbsolutePath(connection, path,
         connection->buffer, HTTP_SERVER_BUFFER_SIZE);

      //Open the file for reading
      file = fsOpenFile(connection->buffer, FS_FILE_MODE_READ);

      //Successful operation?
      if(file)
      {
         //Send the contents of the requested file
         while(1)
         {
            //Read data from the specified file
            error = fsReadFile(file, connection->buffer, HTTP_SERVER_BUFFER_SIZE, &length);
            //End of input stream?
            if(error) break;

            //Send data to the client
            error = httpWriteStream(connection, connection->buffer, length);
            //Any error to report?
            if(error) break;
         }

         //Close the file
         fsCloseFile(file);

         //Successful file transfer?
         if(error == ERROR_END_OF_STREAM)
            error = NO_ERROR;
      }
      else
      {
         //The specified URI cannot be found
         error = ERROR_NOT_FOUND;
      }
#else
      uint8_t *data;

      //Retrieve the full pathname
      httpGetAbsolutePath(connection, path,
         connection->buffer, HTTP_SERVER_BUFFER_SIZE);

      //Get the resource data associated with the file
      error = resGetData(connection->buffer, &data, &length);

      //Send the contents of the requested file
      if(!error)
         error = httpWriteStream(connection, data, length);
#endif
   }

   //Cannot found the specified resource?
   if(error == ERROR_NOT_FOUND)
      error = ERROR_INVALID_TAG;

   //Release previously allocated memory
   osFreeMem(path);
   //return status code
   return error;
}