diff --git a/SConscript b/SConscript
index 9444732..7ddb851 100644
--- a/SConscript
+++ b/SConscript
@@ -35,7 +35,7 @@ import os
import GenApps
# imports from SConstruct
-Import('env libFileName elfFileName binDir coreDir driversDir genDir appBase toolsList chuncksNbits sourcesMap gzipped test')
+Import('env libFileName elfFileName binDir coreDir driversDir genDir appBase toolsList chuncksNbits dirsMap sourcesMap restrictMap httpAuthType gzipped test')
# returns the list of .c and .s files in dir, prefixed by dstDir
def getAllSourceFiles(dir, dstDir):
@@ -52,10 +52,25 @@ def getAllSourceFiles(dir, dstDir):
# builders for web applicative resources creation
# used to generate both static and dynamic resources
def generateResource(target, source, env):
+ realm = ''
+ offsetCount = (-1, -1)
+
+ # Checking for HTTP Authentication data
+ finalUri = sourcesMap[str(source[0])]
+
+ maxlen = 0
+ for r in restrictMap:
+ for uri in restrictMap[r]:
+ if finalUri.startswith(uri) and len(uri) > maxlen:
+ offsetCount = (restrictMap[r][uri][0],
+ restrictMap[r][uri][1])
+ realm = r
+ maxlen = len(uri)
+
if propsFilesMap.has_key(str(source[0])):
- GenApps.generateResource(str(source[0]),str(target[0]),chuncksNbits,gzipped,propsFilesMap[str(source[0])])
+ GenApps.generateResource(str(source[0]),str(target[0]),chuncksNbits,gzipped,propsFilesMap[str(source[0])], httpAuthType, realm, offsetCount, finalUri)
else:
- GenApps.generateResource(str(source[0]),str(target[0]),chuncksNbits,gzipped,None)
+ GenApps.generateResource(str(source[0]),str(target[0]),chuncksNbits,gzipped,None,httpAuthType, realm, offsetCount, finalUri)
return None
# builder used to generate the file index, with the URLs tree
diff --git a/SConstruct b/SConstruct
index d2af229..ae558fd 100644
--- a/SConstruct
+++ b/SConstruct
@@ -35,6 +35,7 @@ import os
import sys
sys.path.append('tools')
import GenApps
+import GenAuthData
from SCons.Errors import BuildError
import sys, string
@@ -66,6 +67,7 @@ toolsDir = 'tools'
tmpBase = 'tmp'
appBase = 'apps'
httpCodesDir = 'httpCodes'
+httpAuthType = ''
# the list of python files used by this SConstruct
toolsList = map(lambda x: os.path.join(toolsDir,x),filter(lambda x: x.endswith('.py'), os.listdir(toolsDir)))
projectName = 'smews'
@@ -81,6 +83,7 @@ opts.Add(BoolVariable('debug', 'Set to 1 to build for debug', False))
opts.Add(BoolVariable('sdump', 'Set to 1 to include stack dump', False))
opts.Add(BoolVariable('test', 'Set to 1 to test the test apps', False))
opts.Add('ipaddr', 'Set the IP address of Smews', None)
+opts.Add('accessfile', 'Set the path to XML-defined restrictions file', None)
# the list of disableable options
disabledHash = {}
disabledHash['timers'] = 'DISABLE_TIMERS'
@@ -190,6 +193,15 @@ for appDir in dirsMap.keys():
appSource = os.path.join(appBase,appDir,file)
sourcesMap[appSource] = os.path.join(dirsMap[appDir],file)
+# Contains a data structure for HTTP authentication restrictions.
+# Refer to GenAuthData.py for more details.
+# TODO: Improve the file generation by stripping the "core/" path and
+# allow automatic generation in gen/target
+restrictMap = { }
+if globalEnv.has_key('accessfile'):
+ httpAuthType = GenAuthData.parseXMLFile(globalEnv['accessfile'])
+ restrictMap = GenAuthData.genHTTPAuthDataFile('core/http_auth_data')
+
# compilation options
globalEnv.Replace(CC = 'gcc')
globalEnv.Replace(AS = 'as')
@@ -203,6 +215,12 @@ else:
globalEnv.Append(CCFLAGS = '-Os -ffunction-sections -fdata-sections -fno-strict-aliasing')
globalEnv.Append(LINKFLAGS = '-Wl,--gc-sections -Wl,--print-gc-sections')
globalEnv.Append(CPPDEFINES = {'CHUNCKS_NBITS' : str(chuncksNbits)})
+
+if httpAuthType == 'basic':
+ globalEnv.Append(CPPDEFINES = { 'HTTP_AUTH' : 'HTTP_AUTH_BASIC' })
+elif httpAuthType == 'digest':
+ globalEnv.Append(CPPDEFINES = { 'HTTP_AUTH' : 'HTTP_AUTH_DIGEST' })
+
for func in toDisable:
globalEnv.Append(CPPDEFINES = { disabledHash[func] : '1'})
if endian:
@@ -235,7 +253,7 @@ for target in targets:
# export variables for external SConscript files
Export('env libFileName elfFileName binDir coreDir driversDir genDir appBase toolsList chuncksNbits sourcesMap gzipped test')
Export('env targetDir binDir projectName elfName')
- Export('dirsMap sourcesMap target sconsBasePath httpCodesDir tmpBase')
+ Export('dirsMap sourcesMap restrictMap httpAuthType target sconsBasePath httpCodesDir tmpBase')
# target dependent SConscript call
SConscript(os.path.join(targetDir,'SConscript'),variant_dir = binDir,duplicate = 0)
# possible web applications SConscript calls
diff --git a/accessfile_example.xml b/accessfile_example.xml
new file mode 100644
index 0000000..a4cfeae
--- /dev/null
+++ b/accessfile_example.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/apps/httpCodes/401.html b/apps/httpCodes/401.html
new file mode 100644
index 0000000..6e53480
--- /dev/null
+++ b/apps/httpCodes/401.html
@@ -0,0 +1,10 @@
+
+
+
+ 401 Authorization required
+
+
+ Error 401: Authorization required
+ Please authenticate
+
+
diff --git a/core/auth.c b/core/auth.c
new file mode 100644
index 0000000..cb322fb
--- /dev/null
+++ b/core/auth.c
@@ -0,0 +1,257 @@
+/*
+ * Copyright or © or Copr. 2008, Simon Duquennoy
+ *
+ * Author e-mail: simon.duquennoy@lifl.fr
+ *
+ * This software is a computer program whose purpose is to design an
+ * efficient Web server for very-constrained embedded system.
+ *
+ * This software is governed by the CeCILL license under French law and
+ * abiding by the rules of distribution of free software. You can use,
+ * modify and/ or redistribute the software under the terms of the CeCILL
+ * license as circulated by CEA, CNRS and INRIA at the following URL
+ * "http://www.cecill.info".
+ *
+ * As a counterpart to the access to the source code and rights to copy,
+ * modify and redistribute granted by the license, users are provided only
+ * with a limited warranty and the software's author, the holder of the
+ * economic rights, and the successive licensors have only limited
+ * liability.
+ *
+ * In this respect, the user's attention is drawn to the risks associated
+ * with loading, using, modifying and/or developing or reproducing the
+ * software by the user in light of its specific status of free software,
+ * that may mean that it is complicated to manipulate, and that also
+ * therefore means that it is reserved for developers and experienced
+ * professionals having in-depth computer knowledge. Users are therefore
+ * encouraged to load and test the software's suitability as regards their
+ * requirements in conditions enabling the security of their systems and/or
+ * data to be ensured and, more generally, to use and operate it in the
+ * same conditions as regards security.
+ *
+ * The fact that you are presently reading this means that you have had
+ * knowledge of the CeCILL license and that you accept its terms.
+ */
+
+/*
+ * Author: Christophe Bacara
+ * `-Mail: christophe.bacara@etudiant.univ-lille1.fr
+ */
+
+#include "auth.h"
+#include "md5.h"
+
+#ifdef HTTP_AUTH
+
+#include "http_auth_data.h"
+
+#if HTTP_AUTH == HTTP_AUTH_BASIC
+CONST_VAR(unsigned char, HttpAuthenticateScheme[]) = "basic";
+
+CONST_VAR(char, HttpAuthenticateHeader[]) = "\
+HTTP/1.1 401 Authorization required\r\nWWW-Authenticate: Basic realm=\
+";
+
+#elif HTTP_AUTH == HTTP_AUTH_DIGEST
+CONST_VAR(unsigned char, HttpAuthenticateScheme[]) = "digest";
+
+CONST_VAR(char, HttpAuthenticateHeader[]) = "\
+HTTP/1.1 401 Authorization required\r\nWWW-Authenticate: Digest realm=\
+";
+
+CONST_VAR(char, HttpAuthenticateHeaderNonce[]) = "\
+, nonce=\
+";
+
+CONST_VAR(char, HttpAuthenticateHeaderStale[]) = "\
+, stale=true\
+";
+
+struct nonce_state_s nonce_state = {
+ .requester = NULL,
+ .nonce = "\0"
+};
+
+#endif
+
+uint32_t http_401_handler_dynamic_header_length(const struct output_handler_t *restricted_handler
+#if HTTP_AUTH == HTTP_AUTH_DIGEST
+ , const uint8_t stale
+#endif
+ )
+{
+ unsigned const char *char_p = restricted_handler->handler_restriction.realm;
+ uint32_t length = 0;
+
+ /* Error checking */
+ if (char_p == NULL)
+ return -1;
+
+ /* Realm length computation */
+ while (*char_p++)
+ ++length;
+
+ /* If realm length is odd, we'll add a space after it */
+ if (length & 1)
+ ++length;
+
+#if HTTP_AUTH == HTTP_AUTH_BASIC
+
+ /* Remaining size computation */
+ length += sizeof (HttpAuthenticateHeader) - 1;
+ length += 2; /* Realm must be double quoted */
+
+#elif HTTP_AUTH == HTTP_AUTH_DIGEST
+
+ /* Remaining size computation */
+ length += sizeof (HttpAuthenticateHeader) - 1;
+ length += sizeof (HttpAuthenticateHeaderNonce) - 1;
+ if (stale)
+ length += sizeof (HttpAuthenticateHeaderStale) - 1;
+
+ length += 32; /* Nonce is a 32-Hex character string */
+ length += 4; /* Realm and nonce must be double quoted. */
+
+#endif
+
+ return length;
+}
+
+uint32_t http_401_handler_length(const struct output_handler_t *restricted_handler
+#if HTTP_AUTH == HTTP_AUTH_DIGEST
+ , const uint8_t stale
+#endif
+ )
+{
+ /* Add the size of remaining bytes */
+ return http_401_handler_dynamic_header_length (restricted_handler
+#if HTTP_AUTH == HTTP_AUTH_DIGEST
+ , stale
+#endif
+ )
+ + CONST_UI32 (GET_FILE (&http_401_handler).length);
+}
+
+#if HTTP_AUTH == HTTP_AUTH_BASIC
+char http_basic_authenticate(const struct output_handler_t *handler,
+ unsigned const char *credentials)
+{
+ unsigned const char *current_credentials;
+ unsigned const char *given_credentials;
+ uint8_t i;
+
+ /* For each valid credentials ... */
+ for (i = handler->handler_restriction.credentials_offset;
+ i < (handler->handler_restriction.credentials_offset
+ + handler->handler_restriction.credentials_count);
+ ++i) {
+
+ current_credentials = http_auth_basic_credentials_data[i];
+ given_credentials = credentials;
+
+ /* String comparison loop */
+ while (*given_credentials == *current_credentials) {
+ /* If we reach end of both string simultaneously, they match. */
+ if (*given_credentials == '\0' && *current_credentials == '\0')
+ return HTTP_AUTHENTICATE_SUCCESS;
+
+ ++given_credentials;
+ ++current_credentials;
+ }
+ }
+
+ return HTTP_AUTHENTICATE_FAILURE;
+}
+
+#elif HTTP_AUTH == HTTP_AUTH_DIGEST
+char http_digest_authenticate(const struct connection *requester,
+ const struct output_handler_t *handler,
+ const struct auth_data_s *auth_data)
+{
+ credentials_digest_t *digest_infos = NULL;
+ uint8_t i, j;
+
+ /* Nonce validity check */
+ for (i = 0; i < NONCE_LEN; ++i)
+ if (auth_data->nonce[i] != nonce_state.nonce[i])
+ return HTTP_AUTHENTICATE_STALE;
+
+ /* User validity check */
+ for (i = handler->handler_restriction.credentials_offset;
+ i < (handler->handler_restriction.credentials_offset
+ + handler->handler_restriction.credentials_count);
+ ++i) {
+
+ if (http_auth_digest_credentials_table[i] != auth_data->username_blob)
+ continue;
+
+ /* Once username has been validated, get the matching credentials */
+ for (j = 0; j < USER_DIGEST_COUNT; ++j) {
+ if (http_auth_digest_credentials_data[j].username_blob == auth_data->username_blob
+ &&
+ http_auth_digest_credentials_data[j].realm == handler->handler_restriction.realm) {
+ digest_infos = (credentials_digest_t *) &http_auth_digest_credentials_data[j];
+ break;
+ }
+ }
+ break;
+ }
+
+ /* No digest informations: invalid username */
+ if (digest_infos == NULL)
+ return HTTP_AUTHENTICATE_FAILURE;
+
+ /* Compute the valid md5 digest :
+ * md5(user_digest:nonce:resource_digest) */
+ md5_init();
+ md5_append((const md5_byte_t *) digest_infos->user_digest, MD5_DIGEST_LEN);
+ md5_append((const md5_byte_t *) ":", 1);
+ md5_append((const md5_byte_t *) nonce_state.nonce, NONCE_LEN);
+ md5_append((const md5_byte_t *) ":", 1);
+ md5_append((const md5_byte_t *) handler->handler_restriction.resource_digest,
+ MD5_DIGEST_LEN);
+ md5_end();
+
+ /* Compare given credentials with computed credentials */
+ for (i = 0; i < MD5_DIGEST_LEN; ++i) {
+ /* WARNING: md5_digest is a 16-byte table, whereas credentials is a classic
+ * C character string !
+ * Don't try something like "credentials[i] == md5_digest[i]" */
+ if (auth_data->response[i] != MD5_DIGEST_GET_NTH_HEXC(i))
+ return HTTP_AUTHENTICATE_FAILURE;
+ }
+
+ return HTTP_AUTHENTICATE_SUCCESS;
+}
+
+void http_auth_gen_nonce()
+{
+ static uint32_t x = 123456789; /* XORSHIFT data */
+ static uint32_t y = 362436069; /* XORSHIFT data */
+ static uint32_t z = 521288629; /* XORSHIFT data */
+ static uint32_t w = 88675123; /* XORSHIFT data */
+ uint32_t tmp;
+ uint8_t i;
+
+ for (i = 0; i < NONCE_LEN; i += 8) {
+ /* Compute xorshift */
+ tmp = x ^ (x << 1);
+ x = y;
+ y = z;
+ z = w;
+ w = w ^ (w >> 19) ^ (tmp ^ (tmp >> 8));
+
+ /* Fill nonce with hex character */
+ nonce_state.nonce[i] = hex_char[(w & 0xf0000000) >> 28];
+ nonce_state.nonce[i + 1] = hex_char[(w & 0x0f000000) >> 24];
+ nonce_state.nonce[i + 2] = hex_char[(w & 0x00f00000) >> 20];
+ nonce_state.nonce[i + 3] = hex_char[(w & 0x000f0000) >> 16];
+ nonce_state.nonce[i + 4] = hex_char[(w & 0x0000f000) >> 12];
+ nonce_state.nonce[i + 5] = hex_char[(w & 0x00000f00) >> 8];
+ nonce_state.nonce[i + 6] = hex_char[(w & 0x000000f0) >> 4];
+ nonce_state.nonce[i + 7] = hex_char[(w & 0x0000000f)];
+ }
+}
+
+#endif
+#endif
diff --git a/core/auth.h b/core/auth.h
new file mode 100644
index 0000000..9ab0947
--- /dev/null
+++ b/core/auth.h
@@ -0,0 +1,157 @@
+/*
+ * Copyright or © or Copr. 2008, Simon Duquennoy
+ *
+ * Author e-mail: simon.duquennoy@lifl.fr
+ *
+ * This software is a computer program whose purpose is to design an
+ * efficient Web server for very-constrained embedded system.
+ *
+ * This software is governed by the CeCILL license under French law and
+ * abiding by the rules of distribution of free software. You can use,
+ * modify and/ or redistribute the software under the terms of the CeCILL
+ * license as circulated by CEA, CNRS and INRIA at the following URL
+ * "http://www.cecill.info".
+ *
+ * As a counterpart to the access to the source code and rights to copy,
+ * modify and redistribute granted by the license, users are provided only
+ * with a limited warranty and the software's author, the holder of the
+ * economic rights, and the successive licensors have only limited
+ * liability.
+ *
+ * In this respect, the user's attention is drawn to the risks associated
+ * with loading, using, modifying and/or developing or reproducing the
+ * software by the user in light of its specific status of free software,
+ * that may mean that it is complicated to manipulate, and that also
+ * therefore means that it is reserved for developers and experienced
+ * professionals having in-depth computer knowledge. Users are therefore
+ * encouraged to load and test the software's suitability as regards their
+ * requirements in conditions enabling the security of their systems and/or
+ * data to be ensured and, more generally, to use and operate it in the
+ * same conditions as regards security.
+ *
+ * The fact that you are presently reading this means that you have had
+ * knowledge of the CeCILL license and that you accept its terms.
+ */
+
+/*
+ * Author: Christophe Bacara
+ * `-Mail: christophe.bacara@etudiant.univ-lille1.fr
+ */
+
+#ifndef __AUTH_H__
+#define __AUTH_H__
+
+#define HTTP_AUTH_BASIC 0
+#define HTTP_AUTH_DIGEST 1
+
+#include "handlers.h"
+#include "connections.h"
+#include "types.h"
+
+/* Readability++ macros */
+#define IS_RESTRICTED(handler) (handler->handler_restriction.realm)
+
+#define HTTP_AUTHENTICATE_SUCCESS 1
+#define HTTP_AUTHENTICATE_FAILURE 0
+#define NO_OFFSET (127) /* Useful for parsing nonce/response in input.c */
+
+/* Shortcut to the http 401 handler */
+#define http_401_handler apps_httpCodes_401_html_handler
+
+struct auth_data_s {
+ uint8_t scheme_parsed: 1; /* Flag set on 1 if scheme has been parsed */
+ uint8_t parsing_offset: 7; /* Offset into fields while parsing */
+#if HTTP_AUTH == HTTP_AUTH_BASIC
+ unsigned char *credentials; /* Dynamically allocated storage for
+ * basic credentials: b64(user:passwd) */
+#elif HTTP_AUTH == HTTP_AUTH_DIGEST
+ uint8_t username_blob; /* Username identifier in blob tree */
+ unsigned char response[32]; /* Response digest as given by the client */
+ unsigned char nonce[32]; /* Nonce used by the client to compute digest */
+#endif
+};
+
+/* Http 401 handler */
+extern CONST_VAR(struct output_handler_t, apps_httpCodes_401_html_handler);
+
+/* Store the character string representation of the authentication scheme */
+extern CONST_VAR(unsigned char, HttpAuthenticateScheme[]);
+/* Store the character string representation of the http authenticate header */
+extern CONST_VAR(char, HttpAuthenticateHeader[]);
+
+/* Returns the length of the 401 handler that matches the specified
+ * restricted handler, including the dynamically generated http header with
+ * correct realm and nonce (if digest auth). */
+extern uint32_t http_401_handler_length(const struct output_handler_t *restricted_handler
+#if HTTP_AUTH == HTTP_AUTH_DIGEST
+ , const uint8_t stale
+#endif
+ );
+
+/* Returns the length of the dynamically generated http header for a 401 handler. */
+extern uint32_t http_401_handler_dynamic_header_length(const struct output_handler_t *restricted_handler
+#if HTTP_AUTH == HTTP_AUTH_DIGEST
+ , const uint8_t stale
+#endif
+ );
+
+/*************************************************************************/
+/********************* AUTHENTICATION KIND SPECIFICS *********************/
+/*************************************************************************/
+
+/*********************** BASIC AUTHENTICATION DATA ***********************/
+#if HTTP_AUTH == HTTP_AUTH_BASIC
+
+#define HTTP_AUTHENTICATE_HEADER_LEN 68
+#define HTTP_AUTHENTICATE_HEADER_CHK 0x428Cu
+
+/* Returns 1 if given credentials are valid for the requested handler, 0 if not. */
+extern char http_basic_authenticate(const struct output_handler_t *handler,
+ unsigned const char *credentials);
+
+/*********************** DIGEST AUTHENTICATION DATA **********************/
+#elif HTTP_AUTH == HTTP_AUTH_DIGEST
+
+#define HTTP_AUTHENTICATE_STALE -1
+
+#define HTTP_AUTHENTICATE_HEADER_LEN 68
+#define HTTP_AUTHENTICATE_HEADER_CHK 0x9A92u
+
+extern CONST_VAR(char, HttpAuthenticateHeaderNonce[]);
+extern CONST_VAR(char, HttpAuthenticateHeaderStale[]);
+
+#define HTTP_AUTHENTICATE_HEADER_NONCE_LEN 8
+#define HTTP_AUTHENTICATE_HEADER_NONCE_CHK 0x6E30u
+
+#define HTTP_AUTHENTICATE_HEADER_STALE_LEN 12
+#define HTTP_AUTHENTICATE_HEADER_STALE_CHK 0x5016u
+
+#define NONCE_LEN 32
+
+/* Digest authentication data structure */
+typedef struct credentials_digest_s {
+ const uint8_t username_blob; /* Corresponding blob into users blob tree */
+ const unsigned char *realm; /* Realm for which this credentials stand */
+ const unsigned char user_digest[33]; /* Digest for this user & realm. */
+} credentials_digest_t;
+
+/* Nonce control structure */
+extern struct nonce_state_s {
+ struct connection *requester; /* Last connection requesting a nonce */
+ unsigned char nonce[NONCE_LEN]; /* Last nonce generated */
+} nonce_state;
+
+/* Returns 1 if given credentials are valid for the requested handler, 0 if not.
+ * Returns -1 if nonce is not valid (response will contain "stale" in WWW-Auth) */
+extern char http_digest_authenticate(const struct connection *requester,
+ const struct output_handler_t *handler,
+ const struct auth_data_s *auth_data);
+
+/* Generate a new nonce based on a xorshift randomizer. */
+extern void http_auth_gen_nonce();
+
+#endif
+/**************************** END OF SPECIFICS ***************************/
+
+#endif
+
diff --git a/core/connections.h b/core/connections.h
index ef09b51..aa64bb9 100644
--- a/core/connections.h
+++ b/core/connections.h
@@ -1,41 +1,42 @@
/*
-* Copyright or © or Copr. 2008, Simon Duquennoy
-*
-* Author e-mail: simon.duquennoy@lifl.fr
-*
-* This software is a computer program whose purpose is to design an
-* efficient Web server for very-constrained embedded system.
-*
-* This software is governed by the CeCILL license under French law and
-* abiding by the rules of distribution of free software. You can use,
-* modify and/ or redistribute the software under the terms of the CeCILL
-* license as circulated by CEA, CNRS and INRIA at the following URL
-* "http://www.cecill.info".
-*
-* As a counterpart to the access to the source code and rights to copy,
-* modify and redistribute granted by the license, users are provided only
-* with a limited warranty and the software's author, the holder of the
-* economic rights, and the successive licensors have only limited
-* liability.
-*
-* In this respect, the user's attention is drawn to the risks associated
-* with loading, using, modifying and/or developing or reproducing the
-* software by the user in light of its specific status of free software,
-* that may mean that it is complicated to manipulate, and that also
-* therefore means that it is reserved for developers and experienced
-* professionals having in-depth computer knowledge. Users are therefore
-* encouraged to load and test the software's suitability as regards their
-* requirements in conditions enabling the security of their systems and/or
-* data to be ensured and, more generally, to use and operate it in the
-* same conditions as regards security.
-*
-* The fact that you are presently reading this means that you have had
-* knowledge of the CeCILL license and that you accept its terms.
-*/
+ * Copyright or © or Copr. 2008, Simon Duquennoy
+ *
+ * Author e-mail: simon.duquennoy@lifl.fr
+ *
+ * This software is a computer program whose purpose is to design an
+ * efficient Web server for very-constrained embedded system.
+ *
+ * This software is governed by the CeCILL license under French law and
+ * abiding by the rules of distribution of free software. You can use,
+ * modify and/ or redistribute the software under the terms of the CeCILL
+ * license as circulated by CEA, CNRS and INRIA at the following URL
+ * "http://www.cecill.info".
+ *
+ * As a counterpart to the access to the source code and rights to copy,
+ * modify and redistribute granted by the license, users are provided only
+ * with a limited warranty and the software's author, the holder of the
+ * economic rights, and the successive licensors have only limited
+ * liability.
+ *
+ * In this respect, the user's attention is drawn to the risks associated
+ * with loading, using, modifying and/or developing or reproducing the
+ * software by the user in light of its specific status of free software,
+ * that may mean that it is complicated to manipulate, and that also
+ * therefore means that it is reserved for developers and experienced
+ * professionals having in-depth computer knowledge. Users are therefore
+ * encouraged to load and test the software's suitability as regards their
+ * requirements in conditions enabling the security of their systems and/or
+ * data to be ensured and, more generally, to use and operate it in the
+ * same conditions as regards security.
+ *
+ * The fact that you are presently reading this means that you have had
+ * knowledge of the CeCILL license and that you accept its terms.
+ */
#ifndef __CONNECTIONS_H__
#define __CONNECTIONS_H__
+#include "auth.h"
#include "handlers.h"
#include "coroutines.h"
@@ -54,150 +55,196 @@
#ifndef DISABLE_POST
/* Boundary structure (for multipart) */
struct boundary_t {
- char *boundary_ref; /* boundary which separates parts in multipart post data */
- char *boundary_buffer; /* buffer used to detect boundary */
- uint8_t boundary_size; /* size of boundary */
- uint8_t index;
- uint8_t ready_to_count; /* true when post header is parsed */
- uint8_t multi_part_counter; /* to know index of part parsed */
+ char *boundary_ref; /* boundary which separates parts in multipart post data */
+ char *boundary_buffer; /* buffer used to detect boundary */
+ uint8_t boundary_size; /* size of boundary */
+ uint8_t index;
+ uint8_t ready_to_count; /* true when post header is parsed */
+ uint8_t multi_part_counter; /* to know index of part parsed */
};
/* Post data structure */
struct post_data_t {
- uint16_t content_length;
- struct boundary_t *boundary;
- struct coroutine_t coroutine;
- char *filename; /* filename of current part */
- void *post_data; /* data flowing between dopostin and dopostout functions */
- uint8_t content_type;
+ uint16_t content_length;
+ struct boundary_t *boundary;
+ struct coroutine_t coroutine;
+ char *filename; /* filename of current part */
+ void *post_data; /* data flowing between dopostin and dopostout functions */
+ uint8_t content_type;
};
#endif
/* Possible http headers being used */
-enum service_header_e { header_none, header_standard, header_chunks };
+enum service_header_e { header_none, header_standard, header_chunks, header_authenticate };
/* Information about one in-flight segment (several per service) */
struct in_flight_infos_t {
- unsigned char next_outseqno[4]; /* associated sequence number */
- unsigned char checksum[2]; /* segment checksum */
- union if_infos_e { /* either a coroutine context or a data buffer */
+ unsigned char next_outseqno[4]; /* associated sequence number */
+ unsigned char checksum[2]; /* segment checksum */
+ union if_infos_e { /* either a coroutine context or a data buffer */
#ifndef DISABLE_COROUTINES
- struct cr_context_t *context;
+ struct cr_context_t *context;
#endif
- char *buffer;
- } infos;
- struct in_flight_infos_t *next; /* the next in-flight segment */
- enum service_header_e service_header: 2; /* http header infos */
+ char *buffer;
+ } infos;
+ struct in_flight_infos_t *next; /* the next in-flight segment */
+ enum service_header_e service_header: 2; /* http header infos */
};
struct generator_service_t {
- unsigned char curr_outseqno[4];
+ unsigned char curr_outseqno[4];
#ifndef DISABLE_COROUTINES
- struct coroutine_t coroutine;
+ struct coroutine_t coroutine;
#endif
- struct in_flight_infos_t *in_flight_infos;
- enum service_header_e service_header: 2;
- unsigned is_persistent: 1;
+ struct in_flight_infos_t *in_flight_infos;
+ enum service_header_e service_header: 2;
+ unsigned is_persistent: 1;
};
/* Connection structure */
struct http_connection {
- unsigned tcp_mss: 12;
- unsigned ready_to_send:1;
- enum tcp_state_e {tcp_listen, tcp_syn_rcvd, tcp_established, tcp_closing, tcp_last_ack} tcp_state: 3;
- unsigned char next_outseqno[4];
- unsigned char final_outseqno[4];
- unsigned char current_inseqno[4];
+ unsigned tcp_mss: 12;
+ unsigned ready_to_send:1;
+ enum tcp_state_e {tcp_listen, tcp_syn_rcvd, tcp_established, tcp_closing, tcp_last_ack} tcp_state: 3;
+ unsigned char next_outseqno[4];
+ unsigned char final_outseqno[4];
+ unsigned char current_inseqno[4];
- unsigned char port[2];
- unsigned char cwnd[2];
- unsigned char inflight[2];
+ unsigned char port[2];
+ unsigned char cwnd[2];
+ unsigned char inflight[2];
- unsigned const char * /*CONST_VAR*/ blob;
- struct generator_service_t *generator_service;
+ unsigned const char * /*CONST_VAR*/ blob;
+ struct generator_service_t *generator_service;
#ifndef DISABLE_ARGS
- struct args_t *args;
- unsigned char *curr_arg;
- unsigned char arg_ref_index;
+ struct args_t *args;
+ unsigned char *curr_arg;
+ unsigned char arg_ref_index;
#endif
+
#ifndef DISABLE_TIMERS
- unsigned char transmission_time;
+ unsigned char transmission_time;
#endif
- enum parsing_state_e {parsing_out, parsing_cmd, parsing_url, parsing_end
+
#ifndef DISABLE_POST
- , parsing_post_attributes, parsing_post_end, parsing_post_content_type, parsing_post_args, parsing_post_data, parsing_boundary, parsing_init_buffer } parsing_state: 4;
- uint8_t post_url_detected:1; /* bit used to know if url is post or get request */
- struct post_data_t *post_data;
+ enum parsing_state_e {
+ parsing_out,
+ parsing_cmd,
+ parsing_url,
+ parsing_end,
+#if defined(HTTP_AUTH) && HTTP_AUTH == HTTP_AUTH_DIGEST
+ parsing_authorization_username,
+#endif
+ parsing_post_attributes,
+ parsing_post_end,
+ parsing_post_content_type,
+ parsing_post_args,
+ parsing_post_data,
+ parsing_boundary,
+ parsing_init_buffer,
+ } parsing_state : 4;
+
+ uint8_t post_url_detected : 1;
+ struct post_data_t *post_data;
+#else
+#ifdef HTTP_AUTH
+ enum parsing_state_e {
+ parsing_out,
+ parsing_cmd,
+ parsing_url,
+ parsing_end,
+#if HTTP_AUTH == HTTP_AUTH_DIGEST
+ parsing_authorization_username,
+#endif
+ parsing_post_attributes,
+ parsing_post_end
+ } parsing_state : 3;
#else
-} parsing_state/*: 2*/; /* this field will be on one byte anyway as previous fields are exactly 16 bits.
- Using a full char does not change the struct size, but lower the code size needed to access it */
+ enum parsing_state_e {
+ parsing_out,
+ parsing_cmd,
+ parsing_url,
+ parsing_end
+ } parsing_state : 2;
#endif
+#endif
+
+/* enum parsing_state_e {parsing_out, parsing_cmd, parsing_url, parsing_end */
+/* #ifndef DISABLE_POST */
+/* , parsing_post_attributes, parsing_post_end, parsing_post_content_type, parsing_post_args, parsing_post_data, parsing_boundary, parsing_init_buffer } parsing_state: 4; */
+/* uint8_t post_url_detected:1; /\* bit used to know if url is post or get request *\/ */
+/* struct post_data_t *post_data; */
+/* #else */
+/* } parsing_state/\*: 2*\/; /\* this field will be on one byte anyway as previous fields are exactly 16 bits. */
+/* Using a full char does not change the struct size, but lower the code size needed to access it *\/ */
+/* #endif */
+
#ifndef DISABLE_COMET
- unsigned char comet_passive: 1;
- unsigned char comet_send_ack: 1;
- unsigned char comet_streaming: 1;
+ unsigned char comet_passive: 1;
+ unsigned char comet_send_ack: 1;
+ unsigned char comet_streaming: 1;
#endif
};
#ifndef DISABLE_GP_IP_HANDLER
struct gp_ip_connection {
- uint16_t payload_size;
- uint8_t protocol;
- uint8_t want_to_send;
+ uint16_t payload_size;
+ uint8_t protocol;
+ uint8_t want_to_send;
};
#endif
/* Generic connection structure */
struct connection {
#ifndef IPV6
- unsigned char ip_addr[4];
+ unsigned char ip_addr[4];
#endif
- const struct output_handler_t * /*CONST_VAR*/ output_handler;
- union {
+ const struct output_handler_t * /*CONST_VAR*/ output_handler;
+ union {
#ifndef DISABLE_GP_IP_HANDLER
- struct gp_ip_connection gpip;
+ struct gp_ip_connection gpip;
#endif
- struct http_connection http;
- } protocol;
+ struct http_connection http;
+ } protocol;
- struct connection *next;
- struct connection *prev;
+ struct connection *next;
+ struct connection *prev;
#ifdef IPV6
- unsigned char ip_addr[0];
+ unsigned char ip_addr[0];
#endif
};
#ifndef DISABLE_GP_IP_HANDLER
- #define IS_GPIP(connection) (connection && connection->output_handler && IS_GPIP_HANDLER(connection->output_handler))
- #define IS_HTTP(connection) (!IS_GPIP(connection))
+#define IS_GPIP(connection) (connection && connection->output_handler && IS_GPIP_HANDLER(connection->output_handler))
+#define IS_HTTP(connection) (!IS_GPIP(connection))
#else
- #define IS_HTTP(connection) (connection)
+#define IS_HTTP(connection) (connection)
#endif
/* Loop on each connection */
-#define FOR_EACH_CONN(item, code) \
- if(all_connections) { \
- struct connection *(item) = all_connections; \
- do { \
- {code} \
- (item) = (item)->next; \
- } while((item) != all_connections); \
- } \
+#define FOR_EACH_CONN(item, code) \
+ if(all_connections) { \
+ struct connection *(item) = all_connections; \
+ do { \
+ {code} \
+ (item) = (item)->next; \
+ } while((item) != all_connections); \
+ } \
#define NEXT_CONN(item) (item) = (item)->next
/* Pseudo connection for RST */
struct http_rst_connection {
#ifdef IPV6
- unsigned char ip_addr[16];
+ unsigned char ip_addr[16];
#else
- unsigned char ip_addr[4];
+ unsigned char ip_addr[4];
#endif
- unsigned char current_inseqno[4];
- unsigned char next_outseqno[4];
- unsigned char port[2];
+ unsigned char current_inseqno[4];
+ unsigned char next_outseqno[4];
+ unsigned char port[2];
};
/* Shared global connections structures */
@@ -208,16 +255,16 @@ extern struct http_rst_connection rst_connection;
struct curr_output_t {
- struct generator_service_t *service;
- char *buffer;
- unsigned char checksum[2];
- uint16_t content_length;
- uint16_t max_bytes;
- unsigned char next_outseqno[4];
- enum service_header_e service_header: 2;
+ struct generator_service_t *service;
+ char *buffer;
+ unsigned char checksum[2];
+ uint16_t content_length;
+ uint16_t max_bytes;
+ unsigned char next_outseqno[4];
+ enum service_header_e service_header: 2;
#ifdef DISABLE_COROUTINES
- enum dynamic_state {none, in_dynamic, sending_segment,waiting_ack, ack_received, connection_terminated} dynamic_service_state:3;
- unsigned char in_handler:1;
+ enum dynamic_state {none, in_dynamic, sending_segment,waiting_ack, ack_received, connection_terminated} dynamic_service_state:3;
+ unsigned char in_handler:1;
#endif
};
@@ -235,11 +282,11 @@ extern unsigned char * decompress_ip(const unsigned char comp_ip_addr[], unsigne
extern unsigned char * compress_ip(const unsigned char full_ip_addr[], unsigned char comp_ip_addr[], unsigned char * indexes);
static inline uint8_t compressed_ip_size(const unsigned char ip[])
{
- return (17-((ip[0])&15));
+ return (17-((ip[0])&15));
}
static inline unsigned char * copy_compressed_ip(unsigned char dst[], const unsigned char src[])
{
- return memcpy(dst, src, compressed_ip_size(src));
+ return memcpy(dst, src, compressed_ip_size(src));
}
@@ -255,10 +302,10 @@ extern void free_connection(const struct connection *connection);
/* Allocates and insert a new connection. The inserted connection will be a copy of the from parameter */
extern struct connection *add_connection(const struct connection *from
#ifdef IPV6
- , uint8_t compressed_ip_size /* Used in ipv6 to allocation enough bytes to
- store the compressed ip */
+ , uint8_t compressed_ip_size /* Used in ipv6 to allocation enough bytes to
+ store the compressed ip */
#endif
- );
+ );
/* deallocate all the memory used by in-flight segments that are now acknowledged (with out_seqno < inack) */
extern void clean_service(struct generator_service_t *service, unsigned char inack[]);
@@ -266,7 +313,7 @@ extern void clean_service(struct generator_service_t *service, unsigned char ina
#ifndef DISABLE_POST
/* Shared coroutine state (in = 0 / out = 1)*/
struct coroutine_state_t {
- enum coroutine_state_e {cor_in, cor_out} state:1;
+ enum coroutine_state_e {cor_in, cor_out} state:1;
};
extern struct coroutine_state_t coroutine_state;
#endif
diff --git a/core/handlers.h b/core/handlers.h
index 91140c4..cbb466b 100644
--- a/core/handlers.h
+++ b/core/handlers.h
@@ -59,17 +59,17 @@ typedef char (generator_dopost_out_func_t)(uint8_t,void *);
/* Generator: init and run functions */
struct dynamic_resource {
- generator_init_func_t *init;
- union handlers_u {
- struct get_handlers {
- generator_initget_func_t *initget;
- generator_doget_func_t *doget;
- } get;
+ generator_init_func_t *init;
+ union handlers_u {
+ struct get_handlers {
+ generator_initget_func_t *initget;
+ generator_doget_func_t *doget;
+ } get;
#ifndef DISABLE_POST
- struct post_handlers{
- generator_dopost_in_func_t *dopostin;
- generator_dopost_out_func_t *dopostout;
- } post;
+ struct post_handlers{
+ generator_dopost_in_func_t *dopostin;
+ generator_dopost_out_func_t *dopostout;
+ } post;
#endif
#ifndef DISABLE_GP_IP_HANDLER
struct gp_ip_handlers {
@@ -136,7 +136,7 @@ struct output_handler_t {
const struct dynamic_resource generator;
} handler_data;
#ifndef DISABLE_ARGS
- struct handler_args_t {
+ struct handler_args_t {
unsigned const char * /*CONST_VAR*/ args_tree;
const struct arg_ref_t * /*CONST_VAR*/ args_index;
uint16_t args_size;
@@ -148,6 +148,17 @@ struct output_handler_t {
uint8_t mimes_size;
}handler_mimes;
#endif
+#ifdef HTTP_AUTH
+ struct handler_restriction_t {
+ unsigned const char *realm; /* Realm of restriction :
+ - no restriction if NULL */
+ uint8_t credentials_offset; /* Offset to the first credential */
+ uint8_t credentials_count; /* Credentials count from offset */
+#if HTTP_AUTH == HTTP_AUTH_DIGEST
+ unsigned const char resource_digest[33]; /* Digest of md5("METHOD:uri") */
+#endif
+ } handler_restriction;
+#endif
};
#ifndef DISABLE_GP_IP_HANDLER
diff --git a/core/input.c b/core/input.c
index b718c54..c1694e3 100644
--- a/core/input.c
+++ b/core/input.c
@@ -42,6 +42,14 @@
#include "coroutines.h"
#include "blobs.h"
#include "defines.h"
+#include "utils.h"
+
+#ifdef HTTP_AUTH
+#include "auth.h"
+#include "md5.h"
+#endif
+
+#include
/* Used to dump the runtime stack */
#ifdef STACK_DUMP
@@ -57,7 +65,7 @@ extern CONST_VAR(struct output_handler_t, apps_httpCodes_404_html_handler);
#ifndef DEV_MTU
#define MAX_MSS 0xffff
#else
-#define MAX_MSS (DEV_MTU - (IP_HEADER_SIZE+ TCP_HEADER_SIZE))
+#define MAX_MSS (DEV_MTU - (IP_HEADER_SIZE + TCP_HEADER_SIZE))
#endif
/* IP and TCP constants */
@@ -73,7 +81,7 @@ extern CONST_VAR(struct output_handler_t, apps_httpCodes_404_html_handler);
/* Initial sequence number */
#define BASIC_SEQNO 0x42b7a491
-#ifndef DISABLE_POST
+#if !defined(DISABLE_POST) || defined(HTTP_AUTH)
#define URL_POST_END 255
#define HEADER_POST_END 128
static CONST_VAR(unsigned char, blob_http_header_end[]) = {13,10,13,128};
@@ -84,97 +92,97 @@ extern CONST_VAR(struct output_handler_t, apps_httpCodes_505_html_handler);
/* gets 16 bits and checks if nothing wrong appened */
static char dev_get16(unsigned char *word) {
- int16_t tmp;
- DEV_GET(tmp);
- if(tmp == -1)
- return -1;
- word[1] = tmp;
- DEV_GET(tmp);
- if(tmp == -1)
- return -1;
- word[0] = tmp;
- return 1;
+ int16_t tmp;
+ DEV_GET(tmp);
+ if(tmp == -1)
+ return -1;
+ word[1] = tmp;
+ DEV_GET(tmp);
+ if(tmp == -1)
+ return -1;
+ word[0] = tmp;
+ return 1;
}
/* gets 32 bits and checks if nothing wrong appened */
static char dev_get32(unsigned char *dword) {
- if(dev_get16(&dword[2]) == -1)
- return -1;
- if(dev_get16(&dword[0]) == -1)
- return -1;
- return 1;
+ if(dev_get16(&dword[2]) == -1)
+ return -1;
+ if(dev_get16(&dword[0]) == -1)
+ return -1;
+ return 1;
}
#ifdef IPV6
/* gets 128 bits and checks if nothing wrong appened */
static char dev_get128(unsigned char *dword) {
- if(dev_get32(&dword[12]) == -1)
- return -1;
- if(dev_get32(&dword[8]) == -1)
- return -1;
- if(dev_get32(&dword[4]) == -1)
- return -1;
- if(dev_get32(&dword[0]) == -1)
- return -1;
- return 1;
+ if(dev_get32(&dword[12]) == -1)
+ return -1;
+ if(dev_get32(&dword[8]) == -1)
+ return -1;
+ if(dev_get32(&dword[4]) == -1)
+ return -1;
+ if(dev_get32(&dword[0]) == -1)
+ return -1;
+ return 1;
}
/* Get 2 bytes */
-#define DEV_GET16(c) { \
- if(dev_get16((unsigned char*)(c)) == -1) \
- return 1; \
- }
+#define DEV_GET16(c) { \
+ if(dev_get16((unsigned char*)(c)) == -1) \
+ return 1; \
+ }
/* Get 4 bytes */
-#define DEV_GET32(c) { \
- if(dev_get32((unsigned char*)(c)) == -1) \
- return 1; \
- }
+#define DEV_GET32(c) { \
+ if(dev_get32((unsigned char*)(c)) == -1) \
+ return 1; \
+ }
/* Get 16 bytes */
-#define DEV_GET128(c) { \
- if(dev_get128((unsigned char*)(c)) == -1) \
- return 1; \
- }
+#define DEV_GET128(c) { \
+ if(dev_get128((unsigned char*)(c)) == -1) \
+ return 1; \
+ }
#endif
/* Get and checksum a byte */
#define DEV_GETC(c) { int16_t getc; \
- DEV_GET(getc); \
- if(getc == -1) return 1; \
- c = getc; \
- checksum_add(c);} \
+ DEV_GET(getc); \
+ if(getc == -1) return 1; \
+ c = getc; \
+ checksum_add(c);} \
/* Get and checksum 2 bytes */
-#define DEV_GETC16(c) { \
- if(dev_get16((unsigned char*)(c)) == -1) \
- return 1; \
- checksum_add16(UI16(c)); \
- }
+#define DEV_GETC16(c) { \
+ if(dev_get16((unsigned char*)(c)) == -1) \
+ return 1; \
+ checksum_add16(UI16(c)); \
+ }
/* Get and checksum 4 bytes */
-#define DEV_GETC32(c) { \
- if(dev_get32((unsigned char*)(c)) == -1) \
- return 1; \
- checksum_add32(c); \
- }
+#define DEV_GETC32(c) { \
+ if(dev_get32((unsigned char*)(c)) == -1) \
+ return 1; \
+ checksum_add32(c); \
+ }
#ifdef IPV6
/* Get and checksum 16 bytes */
-#define DEV_GETC128(c) { \
- if(dev_get128((unsigned char*)(c)) == -1) \
- return 1; \
- checksum_add32(&c[12]); \
- checksum_add32(&c[8]); \
- checksum_add32(&c[4]); \
- checksum_add32(&c[0]); \
- }
+#define DEV_GETC128(c) { \
+ if(dev_get128((unsigned char*)(c)) == -1) \
+ return 1; \
+ checksum_add32(&c[12]); \
+ checksum_add32(&c[8]); \
+ checksum_add32(&c[4]); \
+ checksum_add32(&c[0]); \
+ }
#endif
#ifndef DISABLE_POST
struct curr_input_t {
- struct connection *connection;
- uint16_t length;
+ struct connection *connection;
+ uint16_t length;
} curr_input;
#endif
@@ -183,87 +191,87 @@ struct curr_input_t {
* for general purpose ip handler is very simple */
short in()
{
- unsigned char tmp;
- DEV_GET(tmp);
- return tmp;
+ unsigned char tmp;
+ DEV_GET(tmp);
+ return tmp;
}
#endif
#ifndef DISABLE_POST
/* called from dopostin or dopacketin */
short in(){
- unsigned char tmp;
+ unsigned char tmp;
#ifndef DISABLE_GP_IP_HANDLER
- /* If post AND general purpose ip, then check if the connection is null
- * if so, it is called from packetin */
- if (curr_input.connection == NULL)
+ /* If post AND general purpose ip, then check if the connection is null
+ * if so, it is called from packetin */
+ if (curr_input.connection == NULL)
{
- DEV_GET(tmp);
- return tmp;
+ DEV_GET(tmp);
+ return tmp;
}
#endif
- if(coroutine_state.state == cor_out)
- return -1;
- if(!curr_input.connection->protocol.http.post_data->content_length)
- return -1;
- if(curr_input.connection->protocol.http.post_data->boundary && (curr_input.connection->protocol.http.post_data->boundary->index == (uint8_t)-1)) /* index = -1 => boundary found */
- return -1;
- if(!curr_input.length)
- cr_run(NULL,cor_type_get); /* input buffer is empty, changing context */
- if(curr_input.connection->protocol.http.post_data->boundary){
- /* getting next value in input buffer */
- tmp = curr_input.connection->protocol.http.post_data->boundary->boundary_buffer[curr_input.connection->protocol.http.post_data->boundary->index];
- DEV_GETC(curr_input.connection->protocol.http.post_data->boundary->boundary_buffer[curr_input.connection->protocol.http.post_data->boundary->index]);
- curr_input.connection->protocol.http.post_data->boundary->index++;
- /* searching boundary */
- if(curr_input.connection->protocol.http.post_data->boundary->index == curr_input.connection->protocol.http.post_data->boundary->boundary_size)
- curr_input.connection->protocol.http.post_data->boundary->index = 0;
- /* comparing first and last characters of buffer with boundary, then all characters */
- if(curr_input.connection->protocol.http.post_data->boundary->boundary_buffer[(unsigned char)(curr_input.connection->protocol.http.post_data->boundary->index - 1) % curr_input.connection->protocol.http.post_data->boundary->boundary_size]
- == curr_input.connection->protocol.http.post_data->boundary->boundary_ref[curr_input.connection->protocol.http.post_data->boundary->boundary_size-1]
- && curr_input.connection->protocol.http.post_data->boundary->boundary_buffer[curr_input.connection->protocol.http.post_data->boundary->index]
- == curr_input.connection->protocol.http.post_data->boundary->boundary_ref[0]){
- unsigned char index = curr_input.connection->protocol.http.post_data->boundary->index + 1;
- unsigned char i;
- for(i = 1 ; i < curr_input.connection->protocol.http.post_data->boundary->boundary_size-1 ; i++){
- if(index == curr_input.connection->protocol.http.post_data->boundary->boundary_size)
- index = 0;
- if(curr_input.connection->protocol.http.post_data->boundary->boundary_ref[i] != curr_input.connection->protocol.http.post_data->boundary->boundary_buffer[index])
- break;
- index++;
- }
- if(i == curr_input.connection->protocol.http.post_data->boundary->boundary_size-1)
- curr_input.connection->protocol.http.post_data->boundary->index = -1;
- }
+ if(coroutine_state.state == cor_out)
+ return -1;
+ if(!curr_input.connection->protocol.http.post_data->content_length)
+ return -1;
+ if(curr_input.connection->protocol.http.post_data->boundary && (curr_input.connection->protocol.http.post_data->boundary->index == (uint8_t)-1)) /* index = -1 => boundary found */
+ return -1;
+ if(!curr_input.length)
+ cr_run(NULL,cor_type_get); /* input buffer is empty, changing context */
+ if(curr_input.connection->protocol.http.post_data->boundary){
+ /* getting next value in input buffer */
+ tmp = curr_input.connection->protocol.http.post_data->boundary->boundary_buffer[curr_input.connection->protocol.http.post_data->boundary->index];
+ DEV_GETC(curr_input.connection->protocol.http.post_data->boundary->boundary_buffer[curr_input.connection->protocol.http.post_data->boundary->index]);
+ curr_input.connection->protocol.http.post_data->boundary->index++;
+ /* searching boundary */
+ if(curr_input.connection->protocol.http.post_data->boundary->index == curr_input.connection->protocol.http.post_data->boundary->boundary_size)
+ curr_input.connection->protocol.http.post_data->boundary->index = 0;
+ /* comparing first and last characters of buffer with boundary, then all characters */
+ if(curr_input.connection->protocol.http.post_data->boundary->boundary_buffer[(unsigned char)(curr_input.connection->protocol.http.post_data->boundary->index - 1) % curr_input.connection->protocol.http.post_data->boundary->boundary_size]
+ == curr_input.connection->protocol.http.post_data->boundary->boundary_ref[curr_input.connection->protocol.http.post_data->boundary->boundary_size-1]
+ && curr_input.connection->protocol.http.post_data->boundary->boundary_buffer[curr_input.connection->protocol.http.post_data->boundary->index]
+ == curr_input.connection->protocol.http.post_data->boundary->boundary_ref[0]){
+ unsigned char index = curr_input.connection->protocol.http.post_data->boundary->index + 1;
+ unsigned char i;
+ for(i = 1 ; i < curr_input.connection->protocol.http.post_data->boundary->boundary_size-1 ; i++){
+ if(index == curr_input.connection->protocol.http.post_data->boundary->boundary_size)
+ index = 0;
+ if(curr_input.connection->protocol.http.post_data->boundary->boundary_ref[i] != curr_input.connection->protocol.http.post_data->boundary->boundary_buffer[index])
+ break;
+ index++;
+ }
+ if(i == curr_input.connection->protocol.http.post_data->boundary->boundary_size-1)
+ curr_input.connection->protocol.http.post_data->boundary->index = -1;
}
- else
- DEV_GETC(tmp);
- /* updating counters */
- if(curr_input.connection->protocol.http.post_data->content_length != (uint16_t)-1)
- curr_input.connection->protocol.http.post_data->content_length--;
- curr_input.length--;
- return tmp;
+ }
+ else
+ DEV_GETC(tmp);
+ /* updating counters */
+ if(curr_input.connection->protocol.http.post_data->content_length != (uint16_t)-1)
+ curr_input.connection->protocol.http.post_data->content_length--;
+ curr_input.length--;
+ return tmp;
}
#endif
#ifndef DISABLE_GP_IP_HANDLER
const struct output_handler_t *smews_gpip_get_output_handler(uint8_t protocol)
{
- /* Try to find a handler that match the protocol number */
- uint8_t i;
- for (i = 0 ; ; ++i)
- {
- struct output_handler_t *handler = (struct output_handler_t*)CONST_ADDR(resources_index[i]);
- if (handler == NULL)
- return NULL;
- if (!IS_GPIP_HANDLER(handler))
- continue;
- if (CONST_UI8(handler->handler_data.generator.handlers.gp_ip.protocol) == protocol) /* found one */
- return handler;
- }
+ /* Try to find a handler that match the protocol number */
+ uint8_t i;
+ for (i = 0 ; ; ++i)
+ {
+ struct output_handler_t *handler = (struct output_handler_t*)CONST_ADDR(resources_index[i]);
+ if (handler == NULL)
return NULL;
+ if (!IS_GPIP_HANDLER(handler))
+ continue;
+ if (CONST_UI8(handler->handler_data.generator.handlers.gp_ip.protocol) == protocol) /* found one */
+ return handler;
+ }
+ return NULL;
}
/*static struct connection *smews_gpip_get_connection(uint8_t protocol, unsigned char *source_ip)
@@ -284,1170 +292,1620 @@ const struct output_handler_t *smews_gpip_get_output_handler(uint8_t protocol)
/*-----------------------------------------------------------------------------------*/
char smews_receive(void) {
- /* local variables */
- unsigned char current_inseqno[4];
- unsigned char current_inack[4];
- unsigned char tmp_ui32[4];
- unsigned char tmp_ui16[2];
- uint16_t packet_length;
- unsigned char tcp_header_length;
- uint16_t segment_length;
- struct connection *connection;
- unsigned char tmp_char;
- uint16_t x;
- unsigned char new_tcp_data;
+ /* local variables */
+ unsigned char current_inseqno[4];
+ unsigned char current_inack[4];
+ unsigned char tmp_ui32[4];
+ unsigned char tmp_ui16[2];
+ uint16_t packet_length;
+ unsigned char tcp_header_length;
+ uint16_t segment_length;
+ struct connection *connection;
+ unsigned char tmp_blob;
+ unsigned char tmp_char;
+ uint16_t x;
+ unsigned char new_tcp_data;
+
+#ifdef HTTP_AUTH
+ /* (bacara): Temporary solution, this will need to be stored into a
+ * connection struct later */
+ struct auth_data_s auth_data = {
+ .scheme_parsed = 0,
+ .parsing_offset = NO_OFFSET,
+#if HTTP_AUTH == HTTP_AUTH_BASIC
+ .credentials = NULL,
+#elif HTTP_AUTH == HTTP_AUTH_DIGEST
+ .username_blob = 0,
+ .response = { 0 },
+ .nonce = { 0 },
+#endif
+ };
+#endif
+
#ifndef DISABLE_GP_IP_HANDLER
- uint8_t protocol;
+ uint8_t protocol;
#endif
#ifdef IPV6
- /* Full and compressed IPv6 adress of the received packet */
- unsigned char full_ipv6_addr[16];
- unsigned char comp_ipv6_addr[17]; /* 16 bytes (addr) + 1 byte (compression indexes) = 17 bytes */
+ /* Full and compressed IPv6 adress of the received packet */
+ unsigned char full_ipv6_addr[16];
+ unsigned char comp_ipv6_addr[17]; /* 16 bytes (addr) + 1 byte (compression indexes) = 17 bytes */
#endif
- /* variables used to defer processing with side effects until the incomming packet has been checked (with checksum) */
- unsigned char defer_clean_service = 0;
- unsigned char defer_free_handler = 0;
+ /* variables used to defer processing with side effects until the incomming packet has been checked (with checksum) */
+ unsigned char defer_clean_service = 0;
+ unsigned char defer_free_handler = 0;
#ifndef DISABLE_ARGS
- struct args_t *defer_free_args;
- uint16_t defer_free_args_size;
+ struct args_t *defer_free_args;
+ uint16_t defer_free_args_size;
#endif
- /* tmp connection used to store the current state until checksums are checked */
- struct connection tmp_connection;
+ /* tmp connection used to store the current state until checksums are checked */
+ struct connection tmp_connection;
- if(!DEV_DATA_TO_READ)
- return 0;
+ if(!DEV_DATA_TO_READ)
+ return 0;
+
+ printf("##### SMEWS IS RECEIVING A PACKET #####\n");
#ifdef IPV6
- /* Get IP Version (and 4 bits of the traffic class) */
- DEV_GET(tmp_char);
+ /* Get IP Version (and 4 bits of the traffic class) */
+ DEV_GET(tmp_char);
#else
- checksum_init();
+ checksum_init();
- /* get IP version & header length */
- DEV_GETC(tmp_char);
+ /* get IP version & header length */
+ DEV_GETC(tmp_char);
#endif
#ifdef SMEWS_RECEIVING
- SMEWS_RECEIVING;
+ SMEWS_RECEIVING;
#endif
- /* Starting to decode IP */
+ /* Starting to decode IP */
#ifdef IPV6
- /* 0x06 : IPV6, 4 bits right because we don't care (yet?)
- about the Traffic Class */
- if(tmp_char>>4 != 0x6)
+ /* 0x06 : IPV6, 4 bits right because we don't care (yet?)
+ about the Traffic Class */
+ if(tmp_char>>4 != 0x6)
#else
- /* 0x45 : IPv4, no option in header */
- if(tmp_char != 0x45)
+ /* 0x45 : IPv4, no option in header */
+ if(tmp_char != 0x45)
#endif
- return 1;
+ return 1;
#ifdef IPV6
- /* Discard the rest of the traffic class and the Flow Label (still unused) */
- DEV_GET(tmp_char);
- DEV_GET16(tmp_ui16);
+ /* Discard the rest of the traffic class and the Flow Label (still unused) */
+ DEV_GET(tmp_char);
+ DEV_GET16(tmp_ui16);
- /* Get IP packet payload length in len */
- DEV_GET16(((uint16_t *)&packet_length));
+ /* Get IP packet payload length in len */
+ DEV_GET16(((uint16_t *)&packet_length));
- DEV_GET(tmp_char);
- /* What's the next header? */
+ DEV_GET(tmp_char);
+ /* What's the next header? */
#ifndef DISABLE_GP_IP_HANDLER
- protocol = tmp_char;
+ protocol = tmp_char;
#else
- if (tmp_char != IP_PROTO_TCP) /* If not TCP and general purpose IP is disabled, drop packet */
- return 1;
+ if (tmp_char != IP_PROTO_TCP) /* If not TCP and general purpose IP is disabled, drop packet */
+ return 1;
#endif
- /* We don't care about the Hop Limit (TTL) */
- DEV_GET(tmp_char);
+ /* We don't care about the Hop Limit (TTL) */
+ DEV_GET(tmp_char);
- /* get & store IP source address */
- DEV_GET128(&full_ipv6_addr[0]);
+ /* get & store IP source address */
+ DEV_GET128(&full_ipv6_addr[0]);
- /* Compress the received IPv6 adress
- compress_ip(FullIPv6, IP's Offset, Indexe's offset) */
- compress_ip(full_ipv6_addr, comp_ipv6_addr+1, &comp_ipv6_addr[0]);
- /* discard the dest IP */
- DEV_GET32(tmp_ui32);
- DEV_GET32(tmp_ui32);
- DEV_GET32(tmp_ui32);
- DEV_GET32(tmp_ui32);
+ /* Compress the received IPv6 adress
+ compress_ip(FullIPv6, IP's Offset, Indexe's offset) */
+ compress_ip(full_ipv6_addr, comp_ipv6_addr+1, &comp_ipv6_addr[0]);
+ /* discard the dest IP */
+ DEV_GET32(tmp_ui32);
+ DEV_GET32(tmp_ui32);
+ DEV_GET32(tmp_ui32);
+ DEV_GET32(tmp_ui32);
#else
- /* discard IP type of service */
- DEV_GETC(tmp_char);
+ /* discard IP type of service */
+ DEV_GETC(tmp_char);
- /* get IP packet length in len */
- DEV_GETC16(((uint16_t *)&packet_length));
- /* The packet_length is the size of the IP payload, without the IP header size.
- * This make the value homegeneous for IPv4 and IPv6 and simplifies code for TCP segment length calculation (no more #ifndef hacks) */
- packet_length = packet_length - IP_HEADER_SIZE;
+ /* get IP packet length in len */
+ DEV_GETC16(((uint16_t *)&packet_length));
+ /* The packet_length is the size of the IP payload, without the IP header size.
+ * This make the value homegeneous for IPv4 and IPv6 and simplifies code for TCP segment length calculation (no more #ifndef hacks) */
+ packet_length = packet_length - IP_HEADER_SIZE;
- /* discard IP ID */
- DEV_GETC16(tmp_ui16);
+ /* discard IP ID */
+ DEV_GETC16(tmp_ui16);
- /* get IP fragmentation flags (fragmentation is not supported) */
- DEV_GETC16(tmp_ui16);
- if((tmp_ui16[S0] & 0x20) || (tmp_ui16[S0] & 0x1f) != 0)
- return 1;
+ /* get IP fragmentation flags (fragmentation is not supported) */
+ DEV_GETC16(tmp_ui16);
+ if((tmp_ui16[S0] & 0x20) || (tmp_ui16[S0] & 0x1f) != 0)
+ return 1;
- /* get IP fragmentation offset */
- if(tmp_ui16[S1] != 0)
- return 1;
+ /* get IP fragmentation offset */
+ if(tmp_ui16[S1] != 0)
+ return 1;
- /* discard IP TTL */
- DEV_GETC16(tmp_ui16);
+ /* discard IP TTL */
+ DEV_GETC16(tmp_ui16);
#ifndef DISABLE_GP_IP_HANDLER
- protocol = tmp_ui16[S1];
+ protocol = tmp_ui16[S1];
#else
- if(tmp_ui16[S1] != IP_PROTO_TCP) /* If not TCP and general purpose IP is disabled, drop packet */
- return 1;
+ if(tmp_ui16[S1] != IP_PROTO_TCP) /* If not TCP and general purpose IP is disabled, drop packet */
+ return 1;
#endif
- /* discard IP checksum */
- DEV_GETC16(tmp_ui16);
+ /* discard IP checksum */
+ DEV_GETC16(tmp_ui16);
- /* get & store IP source address */
- DEV_GETC32(tmp_connection.ip_addr);
+ /* get & store IP source address */
+ DEV_GETC32(tmp_connection.ip_addr);
- /* discard the IP destination address 2*16*/
- DEV_GETC32(tmp_ui32);
+ /* discard the IP destination address 2*16*/
+ DEV_GETC32(tmp_ui32);
- /* check IP checksum */
- checksum_end();
+ /* check IP checksum */
+ checksum_end();
- if(UI16(current_checksum) != 0xffff)
- return 1;
+ if(UI16(current_checksum) != 0xffff)
+ return 1;
#endif
#ifndef DISABLE_GP_IP_HANDLER
- if (protocol != IP_PROTO_TCP)
+ if (protocol != IP_PROTO_TCP)
{
- /* Finaly, the decision has been made to create a new connection for each packet and to
- * free it after having called the output handler.
- * Previous code left in comments if we change our mind later */
- connection = NULL; /* smews_gpip_get_connection(protocol, NULL);*/
+ /* Finaly, the decision has been made to create a new connection for each packet and to
+ * free it after having called the output handler.
+ * Previous code left in comments if we change our mind later */
+ connection = NULL; /* smews_gpip_get_connection(protocol, NULL);*/
- if (connection == NULL) /* no connection found, create one */
+ if (connection == NULL) /* no connection found, create one */
{
- tmp_connection.output_handler = smews_gpip_get_output_handler(protocol);
- if (tmp_connection.output_handler == NULL)
- return 1;
- tmp_connection.protocol.gpip.protocol = protocol;
- /* add the connection */
- connection = add_connection(&tmp_connection
+ tmp_connection.output_handler = smews_gpip_get_output_handler(protocol);
+ if (tmp_connection.output_handler == NULL)
+ return 1;
+ tmp_connection.protocol.gpip.protocol = protocol;
+ /* add the connection */
+ connection = add_connection(&tmp_connection
#ifdef IPV6
- , compressed_ip_size(comp_ipv6_addr)
+ , compressed_ip_size(comp_ipv6_addr)
#endif
- );
- if (connection == NULL)
- return 1;
+ );
+ if (connection == NULL)
+ return 1;
}
- /* update the connection */
+ /* update the connection */
#ifdef IPV6
- copy_compressed_ip(connection->ip_addr, comp_ipv6_addr);
+ copy_compressed_ip(connection->ip_addr, comp_ipv6_addr);
#else
- memcpy(connection->ip_addr, tmp_connection.ip_addr, sizeof(tmp_connection.ip_addr));
+ memcpy(connection->ip_addr, tmp_connection.ip_addr, sizeof(tmp_connection.ip_addr));
#endif
#ifndef DISABLE_POST /* if post is available, must set the curr_input connection to null
so that the in function knows that we are in dopacketin */
- curr_input.connection = NULL;
-#endif
- connection->protocol.gpip.payload_size = packet_length;
- //connection->protocol.gpip.want_to_send = connection->output_handler->handler_data.generator.handlers.gp_ip.dopacketin(connection);
- generator_dopacket_in_func_t *callback = CONST_ADDR(connection->output_handler->handler_data.generator.handlers.gp_ip.dopacketin);
- connection->protocol.gpip.want_to_send = callback(connection);
- if (!connection->protocol.gpip.want_to_send)
- free_connection(connection);
- return 1;
+ curr_input.connection = NULL;
+#endif
+ connection->protocol.gpip.payload_size = packet_length;
+ //connection->protocol.gpip.want_to_send = connection->output_handler->handler_data.generator.handlers.gp_ip.dopacketin(connection);
+ generator_dopacket_in_func_t *callback = CONST_ADDR(connection->output_handler->handler_data.generator.handlers.gp_ip.dopacketin);
+ connection->protocol.gpip.want_to_send = callback(connection);
+ if (!connection->protocol.gpip.want_to_send)
+ free_connection(connection);
+ return 1;
}
#endif
- /* End of IP, starting TCP */
- checksum_init();
+ /* End of IP, starting TCP */
+ checksum_init();
- /* get TCP source port */
- DEV_GETC16(tmp_connection.protocol.http.port);
+ /* get TCP source port */
+ DEV_GETC16(tmp_connection.protocol.http.port);
- /* current connection selection */
- connection = NULL;
- /* search an existing TCP connection using the current port */
+ /* current connection selection */
+ connection = NULL;
+ /* search an existing TCP connection using the current port */
- FOR_EACH_CONN(conn, {
- /* Only search http connection */
- if (!IS_HTTP(conn))
- {
- NEXT_CONN(conn);
- continue;
- }
- if(UI16(conn->protocol.http.port) == UI16(tmp_connection.protocol.http.port) &&
+ FOR_EACH_CONN(conn, {
+ /* Only search http connection */
+ if (!IS_HTTP(conn))
+ {
+ NEXT_CONN(conn);
+ continue;
+ }
+ if(UI16(conn->protocol.http.port) == UI16(tmp_connection.protocol.http.port) &&
#ifdef IPV6
- ipcmp(conn->ip_addr, comp_ipv6_addr)) {
+ ipcmp(conn->ip_addr, comp_ipv6_addr)) {
#else
- UI32(conn->ip_addr) == UI32(tmp_connection.ip_addr)) {
-#endif
- /* connection already existing */
- connection = conn;
- break;
- }
- })
-
- if(connection) {
- /* a connection has been found */
- tmp_connection = *connection;
- } else {
- tmp_connection.protocol.http.tcp_state = tcp_listen;
- tmp_connection.output_handler = NULL;
- UI32(tmp_connection.protocol.http.next_outseqno) = BASIC_SEQNO;
- UI32(tmp_connection.protocol.http.current_inseqno) = 0;
- tmp_connection.protocol.http.parsing_state = parsing_out;
- UI16(tmp_connection.protocol.http.inflight) = 0;
- tmp_connection.protocol.http.generator_service = NULL;
- tmp_connection.protocol.http.ready_to_send = 1;
+ UI32(conn->ip_addr) == UI32(tmp_connection.ip_addr)) {
+#endif
+ /* connection already existing */
+ connection = conn;
+ break;
+ }
+ })
+
+ if(connection) {
+ /* a connection has been found */
+ tmp_connection = *connection;
+ } else {
+ tmp_connection.protocol.http.tcp_state = tcp_listen;
+ tmp_connection.output_handler = NULL;
+ UI32(tmp_connection.protocol.http.next_outseqno) = BASIC_SEQNO;
+ UI32(tmp_connection.protocol.http.current_inseqno) = 0;
+ tmp_connection.protocol.http.parsing_state = parsing_out;
+ UI16(tmp_connection.protocol.http.inflight) = 0;
+ tmp_connection.protocol.http.generator_service = NULL;
+ tmp_connection.protocol.http.ready_to_send = 1;
#ifndef DISABLE_COMET
- tmp_connection.protocol.http.comet_send_ack = 0;
- tmp_connection.protocol.http.comet_passive = 0;
+ tmp_connection.protocol.http.comet_send_ack = 0;
+ tmp_connection.protocol.http.comet_passive = 0;
#endif
#ifndef DISABLE_TIMERS
- tmp_connection.protocol.http.transmission_time = last_transmission_time;
+ tmp_connection.protocol.http.transmission_time = last_transmission_time;
#endif
#ifndef DISABLE_POST
- tmp_connection.protocol.http.post_data = NULL;
- tmp_connection.protocol.http.post_url_detected = 0;
+ tmp_connection.protocol.http.post_data = NULL;
+ tmp_connection.protocol.http.post_url_detected = 0;
#endif
- }
+ }
- /* get and check the destination port */
+ /* get and check the destination port */
- DEV_GETC16(tmp_ui16);
- if(tmp_ui16[S1] != HTTP_PORT) {
+ DEV_GETC16(tmp_ui16);
+ if(tmp_ui16[S1] != HTTP_PORT) {
#ifdef STACK_DUMP
- DEV_PREPARE_OUTPUT(STACK_DUMP_SIZE);
- for(stack_i = 0; stack_i < STACK_DUMP_SIZE ; stack_i++) {
- DEV_PUT(stack_base[-stack_i]);
- }
- DEV_OUTPUT_DONE;
-#endif
- return 1;
+ DEV_PREPARE_OUTPUT(STACK_DUMP_SIZE);
+ for(stack_i = 0; stack_i < STACK_DUMP_SIZE ; stack_i++) {
+ DEV_PUT(stack_base[-stack_i]);
}
+ DEV_OUTPUT_DONE;
+#endif
+ return 1;
+ }
- /* get TCP sequence number */
- DEV_GETC32(current_inseqno);
+ /* get TCP sequence number */
+ DEV_GETC32(current_inseqno);
- /* get TCP ack */
- DEV_GETC32(current_inack);
+ /* get TCP ack */
+ DEV_GETC32(current_inack);
- /* duplicate ACK: set nextoutseqno for retransmission */
- if(UI32(tmp_connection.protocol.http.next_outseqno) - UI16(tmp_connection.protocol.http.inflight) == UI32(current_inack)) {
- UI32(tmp_connection.protocol.http.next_outseqno) = UI32(current_inack);
- }
+ /* duplicate ACK: set nextoutseqno for retransmission */
+ if(UI32(tmp_connection.protocol.http.next_outseqno) - UI16(tmp_connection.protocol.http.inflight) == UI32(current_inack)) {
+ UI32(tmp_connection.protocol.http.next_outseqno) = UI32(current_inack);
+ }
- /* TCP ack management */
- if(UI32(current_inack) && UI32(current_inack) <= UI32(tmp_connection.protocol.http.next_outseqno)) {
- UI16(tmp_connection.protocol.http.inflight) = UI32(tmp_connection.protocol.http.next_outseqno) - UI32(current_inack);
- if(tmp_connection.protocol.http.generator_service) {
- /* deferred because current segment has not yet been checked */
- defer_clean_service = 1;
- }
+ /* TCP ack management */
+ if(UI32(current_inack) && UI32(current_inack) <= UI32(tmp_connection.protocol.http.next_outseqno)) {
+ UI16(tmp_connection.protocol.http.inflight) = UI32(tmp_connection.protocol.http.next_outseqno) - UI32(current_inack);
+ if(tmp_connection.protocol.http.generator_service) {
+ /* deferred because current segment has not yet been checked */
+ defer_clean_service = 1;
}
- /* clear output_handler if needed */
- if(tmp_connection.output_handler && UI16(tmp_connection.protocol.http.inflight) == 0 && !something_to_send(&tmp_connection)) {
- if(tmp_connection.protocol.http.generator_service) {
- /* deferred because current segment has not yet been checked */
- defer_free_handler = 1;
+ }
+ /* clear output_handler if needed */
+ if(tmp_connection.output_handler && UI16(tmp_connection.protocol.http.inflight) == 0 && !something_to_send(&tmp_connection)) {
+ if(tmp_connection.protocol.http.generator_service) {
+ /* deferred because current segment has not yet been checked */
+ defer_free_handler = 1;
#ifndef DISABLE_ARGS
- defer_free_args = tmp_connection.protocol.http.args;
- defer_free_args_size = CONST_UI16(tmp_connection.output_handler->handler_args.args_size);
+ defer_free_args = tmp_connection.protocol.http.args;
+ defer_free_args_size = CONST_UI16(tmp_connection.output_handler->handler_args.args_size);
#endif
- }
+ }
#ifndef DISABLE_COMET
- if(/*tmp_connection.protocol.http.parsing_state == parsing_out &&*/ tmp_connection.protocol.http.comet_streaming == 0) {
- tmp_connection.output_handler = NULL;
- }
-#endif
+ if(/*tmp_connection.protocol.http.parsing_state == parsing_out &&*/ tmp_connection.protocol.http.comet_streaming == 0) {
+ tmp_connection.output_handler = NULL;
}
+#endif
+ }
- /* get TCP offset and flags */
- DEV_GETC16(tmp_ui16);
- tcp_header_length = (tmp_ui16[S0] >> 4) * 4;
-
- /* TCP segment length calculation */
-
- /* packet_length is the length of the IP payload *without* IP headers */
- segment_length = packet_length - tcp_header_length;
-
- if(packet_length - tcp_header_length > 0)
- UI32(current_inseqno) += segment_length;
-
- new_tcp_data = UI32(current_inseqno) > UI32(tmp_connection.protocol.http.current_inseqno);
-
- if(UI32(current_inseqno) >= UI32(tmp_connection.protocol.http.current_inseqno)) {
- UI32(tmp_connection.protocol.http.current_inseqno) = UI32(current_inseqno);
- /* TCP state machine management */
- switch(tmp_connection.protocol.http.tcp_state) {
- case tcp_established:
- if(tmp_ui16[S1] & TCP_FIN) {
- tmp_connection.protocol.http.tcp_state = tcp_last_ack;
- tmp_connection.output_handler = &ref_finack;
- UI32(tmp_connection.protocol.http.current_inseqno)++;
- } else if(tmp_ui16[S1] & TCP_RST) {
- tmp_connection.protocol.http.tcp_state = tcp_listen;
- }
- break;
- case tcp_listen:
- if(tmp_ui16[S1] & TCP_SYN) {
- tmp_connection.protocol.http.tcp_state = tcp_syn_rcvd;
- tmp_connection.output_handler = &ref_synack;
- UI32(tmp_connection.protocol.http.current_inseqno)++;
- }
- break;
- case tcp_syn_rcvd:
- if(UI16(tmp_connection.protocol.http.inflight) == 0) {
- tmp_connection.protocol.http.tcp_state = tcp_established;
- } else {
- tmp_connection.output_handler = &ref_synack;
- }
- break;
- case tcp_last_ack:
- tmp_connection.protocol.http.tcp_state = tcp_listen;
- break;
- default:
- break;
- }
+ /* get TCP offset and flags */
+ DEV_GETC16(tmp_ui16);
+ tcp_header_length = (tmp_ui16[S0] >> 4) * 4;
+
+ /* TCP segment length calculation */
+
+ /* packet_length is the length of the IP payload *without* IP headers */
+ segment_length = packet_length - tcp_header_length;
+
+ if(packet_length - tcp_header_length > 0)
+ UI32(current_inseqno) += segment_length;
+
+ new_tcp_data = UI32(current_inseqno) > UI32(tmp_connection.protocol.http.current_inseqno);
+
+ if(UI32(current_inseqno) >= UI32(tmp_connection.protocol.http.current_inseqno)) {
+ UI32(tmp_connection.protocol.http.current_inseqno) = UI32(current_inseqno);
+ /* TCP state machine management */
+ switch(tmp_connection.protocol.http.tcp_state) {
+ case tcp_established:
+ if(tmp_ui16[S1] & TCP_FIN) {
+ tmp_connection.protocol.http.tcp_state = tcp_last_ack;
+ tmp_connection.output_handler = &ref_finack;
+ UI32(tmp_connection.protocol.http.current_inseqno)++;
+ } else if(tmp_ui16[S1] & TCP_RST) {
+ tmp_connection.protocol.http.tcp_state = tcp_listen;
+ }
+ break;
+ case tcp_listen:
+ if(tmp_ui16[S1] & TCP_SYN) {
+ tmp_connection.protocol.http.tcp_state = tcp_syn_rcvd;
+ tmp_connection.output_handler = &ref_synack;
+ UI32(tmp_connection.protocol.http.current_inseqno)++;
+ }
+ break;
+ case tcp_syn_rcvd:
+ if(UI16(tmp_connection.protocol.http.inflight) == 0) {
+ tmp_connection.protocol.http.tcp_state = tcp_established;
+ } else {
+ tmp_connection.output_handler = &ref_synack;
+ }
+ break;
+ case tcp_last_ack:
+ tmp_connection.protocol.http.tcp_state = tcp_listen;
+ break;
+ default:
+ break;
}
+ }
- /* get the advertissed TCP window in order to limit our sending rate if needed */
- DEV_GETC16(tmp_connection.protocol.http.cwnd);
+ /* get the advertissed TCP window in order to limit our sending rate if needed */
+ DEV_GETC16(tmp_connection.protocol.http.cwnd);
- /* discard the checksum (which is checksummed as other data) and the urgent pointer */
- DEV_GETC32(tmp_ui32);
+ /* discard the checksum (which is checksummed as other data) and the urgent pointer */
+ DEV_GETC32(tmp_ui32);
- /* add the changing part of the TCP pseudo header checksum */
+ /* add the changing part of the TCP pseudo header checksum */
#ifdef IPV6
- checksum_add32(&local_ip_addr[0]);
- checksum_add32(&local_ip_addr[4]);
- checksum_add32(&local_ip_addr[8]);
- checksum_add32(&local_ip_addr[12]);
-
- checksum_add32(&full_ipv6_addr[0]);
- checksum_add32(&full_ipv6_addr[4]);
- checksum_add32(&full_ipv6_addr[8]);
- checksum_add32(&full_ipv6_addr[12]);
+ checksum_add32(&local_ip_addr[0]);
+ checksum_add32(&local_ip_addr[4]);
+ checksum_add32(&local_ip_addr[8]);
+ checksum_add32(&local_ip_addr[12]);
+
+ checksum_add32(&full_ipv6_addr[0]);
+ checksum_add32(&full_ipv6_addr[4]);
+ checksum_add32(&full_ipv6_addr[8]);
+ checksum_add32(&full_ipv6_addr[12]);
#else
- checksum_add32(local_ip_addr);
- checksum_add32(tmp_connection.ip_addr);
+ checksum_add32(local_ip_addr);
+ checksum_add32(tmp_connection.ip_addr);
#endif
- checksum_add16(packet_length);
+ checksum_add16(packet_length);
- /* get TCP mss (for initial negociation) */
- tcp_header_length -= TCP_HEADER_SIZE;
- if(tcp_header_length >= 4) {
- tcp_header_length -= 4;
- DEV_GETC16(tmp_ui16);
- DEV_GETC16(tmp_ui16);
- tmp_connection.protocol.http.tcp_mss = UI16(tmp_ui16) > MAX_MSS ? MAX_MSS : UI16(tmp_ui16);
- }
+ /* get TCP mss (for initial negociation) */
+ tcp_header_length -= TCP_HEADER_SIZE;
+ if(tcp_header_length >= 4) {
+ tcp_header_length -= 4;
+ DEV_GETC16(tmp_ui16);
+ DEV_GETC16(tmp_ui16);
+ tmp_connection.protocol.http.tcp_mss = UI16(tmp_ui16) > MAX_MSS ? MAX_MSS : UI16(tmp_ui16);
+ }
- /* discard the remaining part of the TCP header */
- for(; tcp_header_length > 0; tcp_header_length-=4) {
- DEV_GETC32(tmp_ui32);
- }
+ /* discard the remaining part of the TCP header */
+ for(; tcp_header_length > 0; tcp_header_length-=4) {
+ DEV_GETC32(tmp_ui32);
+ }
- /* End of TCP, starting HTTP */
- x = 0;
- if(segment_length && tmp_connection.protocol.http.tcp_state == tcp_established && (new_tcp_data || tmp_connection.output_handler == NULL)) {
- const struct output_handler_t * /*CONST_VAR*/ output_handler = NULL;
+ /* End of TCP, starting HTTP */
+ x = 0;
+ if(segment_length && tmp_connection.protocol.http.tcp_state == tcp_established && (new_tcp_data || tmp_connection.output_handler == NULL)) {
+ const struct output_handler_t * /*CONST_VAR*/ output_handler = NULL;
- /* parse the eventual GET request */
- unsigned const char * /*CONST_VAR*/ blob;
- unsigned char blob_curr;
+ /* parse the eventual GET request */
+ unsigned const char * /*CONST_VAR*/ blob;
+ unsigned char blob_curr;
#ifndef DISABLE_ARGS
- struct arg_ref_t tmp_arg_ref = {0,0,0};
- uint16_t tmp_args_size_ref;
+ struct arg_ref_t tmp_arg_ref = {0,0,0};
+ uint16_t tmp_args_size_ref;
#endif
- if(tmp_connection.protocol.http.parsing_state == parsing_out) {
+ if(tmp_connection.protocol.http.parsing_state == parsing_out) {
#ifndef DISABLE_ARGS
- tmp_connection.protocol.http.args = NULL;
- tmp_connection.protocol.http.arg_ref_index = 128;
+ tmp_connection.protocol.http.args = NULL;
+ tmp_connection.protocol.http.arg_ref_index = 128;
#endif
- tmp_connection.protocol.http.blob = blob_http_rqt;
- tmp_connection.protocol.http.parsing_state = parsing_cmd;
- tmp_connection.protocol.http.ready_to_send = 1;
- tmp_connection.output_handler = NULL;
+ tmp_connection.protocol.http.blob = blob_http_rqt;
+ tmp_connection.protocol.http.parsing_state = parsing_cmd;
+ tmp_connection.protocol.http.ready_to_send = 1;
+ tmp_connection.output_handler = NULL;
#ifndef DISABLE_POST
- tmp_connection.protocol.http.post_data = NULL;
- tmp_connection.protocol.http.post_url_detected = 0;
+ tmp_connection.protocol.http.post_data = NULL;
+ tmp_connection.protocol.http.post_url_detected = 0;
#endif
- }
- else if(tmp_connection.output_handler)
- output_handler = tmp_connection.output_handler;
- blob = tmp_connection.protocol.http.blob;
+ }
+ else if(tmp_connection.output_handler)
+ output_handler = tmp_connection.output_handler;
+ blob = tmp_connection.protocol.http.blob;
#ifndef DISABLE_ARGS
- if(tmp_connection.protocol.http.arg_ref_index != 128) {
- struct arg_ref_t * /*CONST_VAR*/ tmp_arg_ref_ptr;
- tmp_arg_ref_ptr = &(((struct arg_ref_t*)CONST_ADDR(output_handler->handler_args.args_index))[tmp_connection.protocol.http.arg_ref_index]);
- tmp_arg_ref.arg_type = CONST_UI8(tmp_arg_ref_ptr->arg_type);
- tmp_arg_ref.arg_size = CONST_UI8(tmp_arg_ref_ptr->arg_size);
- tmp_arg_ref.arg_offset = CONST_UI8(tmp_arg_ref_ptr->arg_offset);
- tmp_args_size_ref = CONST_UI16(output_handler->handler_args.args_size);
- }
-#endif
- while(x < segment_length && output_handler != &http_404_handler
-#ifndef DISABLE_POST
- && output_handler != &http_505_handler
+ if(tmp_connection.protocol.http.arg_ref_index != 128) {
+ struct arg_ref_t * /*CONST_VAR*/ tmp_arg_ref_ptr;
+ tmp_arg_ref_ptr = &(((struct arg_ref_t*)CONST_ADDR(output_handler->handler_args.args_index))[tmp_connection.protocol.http.arg_ref_index]);
+ tmp_arg_ref.arg_type = CONST_UI8(tmp_arg_ref_ptr->arg_type);
+ tmp_arg_ref.arg_size = CONST_UI8(tmp_arg_ref_ptr->arg_size);
+ tmp_arg_ref.arg_offset = CONST_UI8(tmp_arg_ref_ptr->arg_offset);
+ tmp_args_size_ref = CONST_UI16(output_handler->handler_args.args_size);
+ }
+#endif
+ while(x < segment_length
+ && output_handler != &http_404_handler
+#ifdef HTTP_AUTH
+ && output_handler != &http_401_handler
#endif
- ) {
- blob_curr = CONST_READ_UI8(blob);
#ifndef DISABLE_POST
- /* testing end multipart */
- if(tmp_connection.protocol.http.post_data
- && tmp_connection.protocol.http.post_data->boundary
- && tmp_connection.protocol.http.post_data->boundary->ready_to_count
- && tmp_connection.protocol.http.post_data->content_length < 3){
- tmp_connection.protocol.http.ready_to_send = 1;
- tmp_connection.protocol.http.parsing_state = parsing_end;
- break;
- }
- if(tmp_connection.protocol.http.parsing_state != parsing_post_data){
-#endif
- x++;
- DEV_GETC(tmp_char);
+ && output_handler != &http_505_handler
+#endif
+ ) {
+ blob_curr = CONST_READ_UI8(blob);
#ifndef DISABLE_POST
- /* updating content length */
- if((tmp_connection.protocol.http.parsing_state == parsing_init_buffer
- || tmp_connection.protocol.http.parsing_state == parsing_post_args
- ||(tmp_connection.protocol.http.post_data
- && tmp_connection.protocol.http.post_data->boundary
- && tmp_connection.protocol.http.post_data->boundary->ready_to_count))
- && tmp_connection.protocol.http.post_data->content_length != (uint16_t)-1)
- tmp_connection.protocol.http.post_data->content_length--;
- }
- /* initializing buffer before parsing data */
- if(tmp_connection.protocol.http.parsing_state == parsing_init_buffer){
- tmp_connection.protocol.http.post_data->boundary->boundary_buffer[tmp_connection.protocol.http.post_data->boundary->index] = tmp_char;
- tmp_connection.protocol.http.post_data->boundary->index++;
- if(tmp_connection.protocol.http.post_data->boundary->index == tmp_connection.protocol.http.post_data->boundary->boundary_size){
- tmp_connection.protocol.http.parsing_state = parsing_post_data;
- /* verifying buffer */
- if(tmp_connection.protocol.http.post_data->boundary->boundary_buffer[(tmp_connection.protocol.http.post_data->boundary->index-1) % tmp_connection.protocol.http.post_data->boundary->boundary_size]
- == tmp_connection.protocol.http.post_data->boundary->boundary_ref[tmp_connection.protocol.http.post_data->boundary->boundary_size-1]
- && tmp_connection.protocol.http.post_data->boundary->boundary_buffer[tmp_connection.protocol.http.post_data->boundary->index]
- == tmp_connection.protocol.http.post_data->boundary->boundary_ref[0]){
- unsigned char index = tmp_connection.protocol.http.post_data->boundary->index + 1;
- unsigned char i;
- for(i = 1 ; i < tmp_connection.protocol.http.post_data->boundary->boundary_size-1 ; i++){
- if(index == tmp_connection.protocol.http.post_data->boundary->boundary_size)
- index = 0;
- if(tmp_connection.protocol.http.post_data->boundary->boundary_ref[i] != tmp_connection.protocol.http.post_data->boundary->boundary_buffer[index])
- break;
- index++;
- }
- if(i == tmp_connection.protocol.http.post_data->boundary->boundary_size-1){
- tmp_connection.protocol.http.parsing_state = parsing_post_attributes;
- blob = blob_http_header_content;
- tmp_connection.protocol.http.post_data->boundary->index = -1;
- }
- }
- }
- else
- continue;
- }
- /* parsing boundary */
- else if(tmp_connection.protocol.http.parsing_state == parsing_boundary){
- if(tmp_connection.protocol.http.post_data->boundary->index == tmp_connection.protocol.http.post_data->boundary->boundary_size)
- tmp_connection.protocol.http.post_data->boundary->index = 0; /* update index */
- /* comparing first and last characters then all */
- if(tmp_connection.protocol.http.post_data->boundary->boundary_buffer[(tmp_connection.protocol.http.post_data->boundary->index-1) % tmp_connection.protocol.http.post_data->boundary->boundary_size]
- == tmp_connection.protocol.http.post_data->boundary->boundary_ref[tmp_connection.protocol.http.post_data->boundary->boundary_size-1]
- && tmp_connection.protocol.http.post_data->boundary->boundary_buffer[tmp_connection.protocol.http.post_data->boundary->index]
- == tmp_connection.protocol.http.post_data->boundary->boundary_ref[0]){
- unsigned char index = tmp_connection.protocol.http.post_data->boundary->index + 1;
- unsigned char i;
- for(i = 1 ; i < tmp_connection.protocol.http.post_data->boundary->boundary_size-1 ; i++){
- if(index == tmp_connection.protocol.http.post_data->boundary->boundary_size)
- index = 0;
- if(tmp_connection.protocol.http.post_data->boundary->boundary_ref[i] != tmp_connection.protocol.http.post_data->boundary->boundary_buffer[index])
- break;
- index++;
- }
- if(i == tmp_connection.protocol.http.post_data->boundary->boundary_size-1){
- tmp_connection.protocol.http.parsing_state = parsing_post_attributes;
- blob = blob_http_header_content;
- tmp_connection.protocol.http.post_data->boundary->index = -1;
- continue;
- }
- }
- tmp_connection.protocol.http.post_data->boundary->boundary_buffer[tmp_connection.protocol.http.post_data->boundary->index] = tmp_char;
- tmp_connection.protocol.http.post_data->boundary->index++;
- continue;
- }
-#endif
- /* search for the web applicative resource to send */
- if(blob_curr >= 128 && output_handler != &http_404_handler
+ /* testing end multipart */
+ if(tmp_connection.protocol.http.post_data
+ && tmp_connection.protocol.http.post_data->boundary
+ && tmp_connection.protocol.http.post_data->boundary->ready_to_count
+ && tmp_connection.protocol.http.post_data->content_length < 3){
+ tmp_connection.protocol.http.ready_to_send = 1;
+ tmp_connection.protocol.http.parsing_state = parsing_end;
+ break;
+ }
+ if(tmp_connection.protocol.http.parsing_state != parsing_post_data){
+#endif
+ x++;
+ DEV_GETC(tmp_char);
+
#ifndef DISABLE_POST
- && output_handler != &http_505_handler
+ /* updating content length */
+ if((tmp_connection.protocol.http.parsing_state == parsing_init_buffer
+ || tmp_connection.protocol.http.parsing_state == parsing_post_args
+ ||(tmp_connection.protocol.http.post_data
+ && tmp_connection.protocol.http.post_data->boundary
+ && tmp_connection.protocol.http.post_data->boundary->ready_to_count))
+ && tmp_connection.protocol.http.post_data->content_length != (uint16_t)-1)
+ tmp_connection.protocol.http.post_data->content_length--;
+ }
+ /* initializing buffer before parsing data */
+ if(tmp_connection.protocol.http.parsing_state == parsing_init_buffer){
+ tmp_connection.protocol.http.post_data->boundary->boundary_buffer[tmp_connection.protocol.http.post_data->boundary->index] = tmp_char;
+ tmp_connection.protocol.http.post_data->boundary->index++;
+ if(tmp_connection.protocol.http.post_data->boundary->index == tmp_connection.protocol.http.post_data->boundary->boundary_size){
+ tmp_connection.protocol.http.parsing_state = parsing_post_data;
+ /* verifying buffer */
+ if(tmp_connection.protocol.http.post_data->boundary->boundary_buffer[(tmp_connection.protocol.http.post_data->boundary->index-1) % tmp_connection.protocol.http.post_data->boundary->boundary_size]
+ == tmp_connection.protocol.http.post_data->boundary->boundary_ref[tmp_connection.protocol.http.post_data->boundary->boundary_size-1]
+ && tmp_connection.protocol.http.post_data->boundary->boundary_buffer[tmp_connection.protocol.http.post_data->boundary->index]
+ == tmp_connection.protocol.http.post_data->boundary->boundary_ref[0]){
+ unsigned char index = tmp_connection.protocol.http.post_data->boundary->index + 1;
+ unsigned char i;
+ for(i = 1 ; i < tmp_connection.protocol.http.post_data->boundary->boundary_size-1 ; i++){
+ if(index == tmp_connection.protocol.http.post_data->boundary->boundary_size)
+ index = 0;
+ if(tmp_connection.protocol.http.post_data->boundary->boundary_ref[i] != tmp_connection.protocol.http.post_data->boundary->boundary_buffer[index])
+ break;
+ index++;
+ }
+ if(i == tmp_connection.protocol.http.post_data->boundary->boundary_size-1){
+ tmp_connection.protocol.http.parsing_state = parsing_post_attributes;
+ blob = blob_http_header_content;
+ tmp_connection.protocol.http.post_data->boundary->index = -1;
+ }
+ }
+ }
+ else
+ continue;
+ }
+ /* parsing boundary */
+ else if(tmp_connection.protocol.http.parsing_state == parsing_boundary){
+ if(tmp_connection.protocol.http.post_data->boundary->index == tmp_connection.protocol.http.post_data->boundary->boundary_size)
+ tmp_connection.protocol.http.post_data->boundary->index = 0; /* update index */
+ /* comparing first and last characters then all */
+ if(tmp_connection.protocol.http.post_data->boundary->boundary_buffer[(tmp_connection.protocol.http.post_data->boundary->index-1) % tmp_connection.protocol.http.post_data->boundary->boundary_size]
+ == tmp_connection.protocol.http.post_data->boundary->boundary_ref[tmp_connection.protocol.http.post_data->boundary->boundary_size-1]
+ && tmp_connection.protocol.http.post_data->boundary->boundary_buffer[tmp_connection.protocol.http.post_data->boundary->index]
+ == tmp_connection.protocol.http.post_data->boundary->boundary_ref[0]){
+ unsigned char index = tmp_connection.protocol.http.post_data->boundary->index + 1;
+ unsigned char i;
+ for(i = 1 ; i < tmp_connection.protocol.http.post_data->boundary->boundary_size-1 ; i++){
+ if(index == tmp_connection.protocol.http.post_data->boundary->boundary_size)
+ index = 0;
+ if(tmp_connection.protocol.http.post_data->boundary->boundary_ref[i] != tmp_connection.protocol.http.post_data->boundary->boundary_buffer[index])
+ break;
+ index++;
+ }
+ if(i == tmp_connection.protocol.http.post_data->boundary->boundary_size-1){
+ tmp_connection.protocol.http.parsing_state = parsing_post_attributes;
+ blob = blob_http_header_content;
+ tmp_connection.protocol.http.post_data->boundary->index = -1;
+ continue;
+ }
+ }
+ tmp_connection.protocol.http.post_data->boundary->boundary_buffer[tmp_connection.protocol.http.post_data->boundary->index] = tmp_char;
+ tmp_connection.protocol.http.post_data->boundary->index++;
+ continue;
+ }
#endif
- ) {
+ /* search for the web applicative resource to send */
+ if(blob_curr >= 128 && output_handler != &http_404_handler
#ifndef DISABLE_POST
- /* "\n\r\n\r" detected (end header or end part of multipart )*/
- if(tmp_connection.protocol.http.parsing_state == parsing_post_end){
- if(tmp_connection.protocol.http.post_data->content_type == (uint8_t)-1){ /* no content type */
- output_handler = &http_505_handler;
- break;
- }
- if(tmp_connection.protocol.http.post_data->boundary){
- tmp_connection.protocol.http.post_data->boundary->ready_to_count = 1;
- /* parsing header part of multipart */
- if(tmp_connection.protocol.http.post_data->content_type == CONTENT_TYPE_MULTIPART_47_FORM_45_DATA){
- tmp_connection.protocol.http.parsing_state = parsing_post_attributes;
- blob = blob_http_header_content;
- continue;
- }
- else
- /* parsing data */
- tmp_connection.protocol.http.parsing_state = parsing_post_data;
- }
- /* parsing form */
- else if(tmp_connection.protocol.http.post_data->content_type == CONTENT_TYPE_APPLICATION_47_X_45_WWW_45_FORM_45_URLENCODED)
- tmp_connection.protocol.http.parsing_state = parsing_post_args;
- else{
- /* no content length detected = boundary is "\r\n\r\n" */
- if(tmp_connection.protocol.http.post_data->content_length == (uint16_t)-1){
- tmp_connection.protocol.http.post_data->boundary = mem_alloc(sizeof(struct boundary_t));
- if(!tmp_connection.protocol.http.post_data->boundary){
- output_handler = &http_404_handler;
- break;
- }
- tmp_connection.protocol.http.post_data->boundary->boundary_size = 4;
- tmp_connection.protocol.http.post_data->boundary->index = -1;
- tmp_connection.protocol.http.post_data->boundary->multi_part_counter = 0;
- tmp_connection.protocol.http.post_data->boundary->boundary_ref = "\r\n\r\n";
- tmp_connection.protocol.http.post_data->boundary->boundary_buffer = mem_alloc(4*sizeof(char));
- if(!tmp_connection.protocol.http.post_data->boundary->boundary_buffer){
- /* If boundary buffer can not be allocated, also free the boundary itself */
- mem_free(tmp_connection.protocol.http.post_data->boundary, sizeof(struct boundary_t));
- output_handler = &http_404_handler;
- break;
- }
- }
- tmp_connection.protocol.http.parsing_state = parsing_post_data;
- }
- }
- /* parsing post data => run coroutine */
- if(tmp_connection.protocol.http.parsing_state == parsing_post_data){
- /* starting buffer init */
- if(tmp_connection.protocol.http.post_data->coroutine.curr_context.status == cr_terminated
- && tmp_connection.protocol.http.post_data->boundary
- && tmp_connection.protocol.http.post_data->boundary->index == 255){
- tmp_connection.protocol.http.post_data->boundary->index = 0;
- tmp_connection.protocol.http.parsing_state = parsing_init_buffer;
- continue;
- }
- uint16_t length_temp = segment_length - x;
- /* initialization coroutine */
- if(tmp_connection.protocol.http.post_data->coroutine.curr_context.status == cr_terminated){
- cr_init(&(tmp_connection.protocol.http.post_data->coroutine));
- tmp_connection.protocol.http.post_data->coroutine.func.func_post_in = CONST_ADDR(GET_GENERATOR(output_handler).handlers.post.dopostin);
- tmp_connection.protocol.http.post_data->coroutine.params.in.content_type = tmp_connection.protocol.http.post_data->content_type;
- tmp_connection.protocol.http.post_data->coroutine.params.in.filename = tmp_connection.protocol.http.post_data->filename;
- tmp_connection.protocol.http.post_data->coroutine.params.in.post_data = tmp_connection.protocol.http.post_data->post_data;
- if(tmp_connection.protocol.http.post_data->boundary){
- tmp_connection.protocol.http.post_data->coroutine.params.in.part_number = tmp_connection.protocol.http.post_data->boundary->multi_part_counter;
- tmp_connection.protocol.http.post_data->boundary->index = 0;
- }
- else
- tmp_connection.protocol.http.post_data->coroutine.params.in.part_number = 0;
- if(cr_prepare(&(tmp_connection.protocol.http.post_data->coroutine)) == NULL)
- {
- /* TODO: shoudn't the boundary and boundary_buffer be free ? */
- return 1;
- }
- }
- curr_input.length = length_temp;
- curr_input.connection = &tmp_connection;
- coroutine_state.state = cor_in;
- /* running coroutine */
- cr_run(&(tmp_connection.protocol.http.post_data->coroutine),cor_type_post_in);
- coroutine_state.state = cor_out;
- x += (length_temp-curr_input.length);
- if(tmp_connection.protocol.http.post_data->coroutine.curr_context.status == cr_terminated){ /* if is terminated */
- tmp_connection.protocol.http.post_data->post_data = tmp_connection.protocol.http.post_data->coroutine.params.in.post_data;
- cr_clean(&(tmp_connection.protocol.http.post_data->coroutine));
- /* cleaning filename memory */
- if(tmp_connection.protocol.http.post_data->filename){
- uint8_t i = 0;
- while(tmp_connection.protocol.http.post_data->filename[i++] != '\0');
- mem_free(tmp_connection.protocol.http.post_data->filename,i*sizeof(char));
- tmp_connection.protocol.http.post_data->filename = NULL;
- }
- /* if no boundary, there is no data to parse */
- if(!tmp_connection.protocol.http.post_data->boundary){
- tmp_connection.protocol.http.parsing_state = parsing_end;
- tmp_connection.protocol.http.ready_to_send = 1;
- }
- else{
- /* starting search of boundary if no found, or ready for next part */
- tmp_connection.protocol.http.post_data->boundary->multi_part_counter++;
- if(tmp_connection.protocol.http.post_data->boundary->index != (uint8_t)-1)
- tmp_connection.protocol.http.parsing_state = parsing_boundary;
- else{
- tmp_connection.protocol.http.parsing_state = parsing_post_attributes;
- blob = blob_http_header_content;
- }
- /* if no content length, parsing is terminated */
- if(tmp_connection.protocol.http.post_data->content_length == (uint16_t)-1){
- tmp_connection.protocol.http.parsing_state = parsing_end;
- tmp_connection.protocol.http.ready_to_send = 1;
- break;
- }
- }
- }
- if(tmp_connection.protocol.http.post_data->boundary)
- continue;
- break;
- }
- /* searching end character of post url detection */
- if(tmp_connection.protocol.http.parsing_state == parsing_url && blob_curr == URL_POST_END){
- if(tmp_connection.protocol.http.post_data){
- tmp_connection.protocol.http.post_url_detected = 1;
- blob_curr = CONST_READ_UI8(++blob);
- }
- else{ /* get unauthorized */
- output_handler = &http_404_handler;
- break;
- }
- }
- /* parsing attributes of post header */
- if(tmp_connection.protocol.http.parsing_state == parsing_post_attributes){
- if(blob_curr == ATTRIBUT_CONTENT_45_TYPE + 128) { /* content-type */
- blob = mimes_tree;
- tmp_connection.protocol.http.parsing_state = parsing_post_content_type;
- }
- else if(blob_curr == ATTRIBUT_CONTENT_45_LENGTH + 128){ /* content-length */
- if(tmp_connection.protocol.http.post_data->content_length == (uint8_t)-1)
- tmp_connection.protocol.http.post_data->content_length = 0;
- if(tmp_char != ' ' && tmp_char != '\r'){
- tmp_connection.protocol.http.post_data->content_length *= 10;
- tmp_connection.protocol.http.post_data->content_length += tmp_char - '0';
- }
- }
- else if(blob_curr == ATTRIBUT_FILENAME_61_ + 128){ /* filename */
- if(!tmp_connection.protocol.http.post_data->filename){
- tmp_connection.protocol.http.post_data->filename = mem_alloc(10 * sizeof(char));
- if(!tmp_connection.protocol.http.post_data->filename){
- output_handler = &http_404_handler;
- break;
- }
- tmp_connection.protocol.http.post_data->filename[0] = 2; /* first value is the size of filename */
- tmp_connection.protocol.http.post_data->filename[1] = 10; /* seconde value is the size allocated */
- }
- else if(tmp_char == '\"'){ /* end of filename, the indexes are removed */
- uint8_t i = 0;
- char *new_tab = mem_alloc((tmp_connection.protocol.http.post_data->filename[0]-1)*sizeof(char));
- if(!new_tab){
- output_handler = &http_404_handler;
- break;
- }
- for(i = 0 ; i < tmp_connection.protocol.http.post_data->filename[0]-2 ; i++)
- new_tab[i] = tmp_connection.protocol.http.post_data->filename[i+2];
- new_tab[i]='\0';
- mem_free(tmp_connection.protocol.http.post_data->filename,(tmp_connection.protocol.http.post_data->filename[1])*sizeof(char));
- tmp_connection.protocol.http.post_data->filename = new_tab;
- tmp_connection.protocol.http.parsing_state = parsing_post_attributes;
- blob = blob_http_header_content;
- }
- else{
- /* reallocating filename */
- if(tmp_connection.protocol.http.post_data->filename[0] == tmp_connection.protocol.http.post_data->filename[1]){
- tmp_connection.protocol.http.post_data->filename = mem_realloc(tmp_connection.protocol.http.post_data->filename,tmp_connection.protocol.http.post_data->filename[1],10);
- if(!tmp_connection.protocol.http.post_data->filename){
- output_handler = &http_404_handler;
- break;
- }
- /* updating size */
- tmp_connection.protocol.http.post_data->filename[1] = tmp_connection.protocol.http.post_data->filename[1] + 10;
- }
- /* add current character */
- tmp_connection.protocol.http.post_data->filename[tmp_connection.protocol.http.post_data->filename[0]] = tmp_char;
- tmp_connection.protocol.http.post_data->filename[0]++;
- }
- }
- /* parsing boundary */
- else if(blob_curr == ATTRIBUT_BOUNDARY_61_ + 128){
- if(tmp_char != '\r'){
- /* reallocating tab */
- if(tmp_connection.protocol.http.post_data->boundary->index == tmp_connection.protocol.http.post_data->boundary->boundary_size){
- tmp_connection.protocol.http.post_data->boundary->boundary_ref = mem_realloc(tmp_connection.protocol.http.post_data->boundary->boundary_ref,tmp_connection.protocol.http.post_data->boundary->boundary_size,10);
- if(!tmp_connection.protocol.http.post_data->boundary->boundary_ref){
- output_handler = &http_404_handler;
- break;
- }
- /* updating size */
- tmp_connection.protocol.http.post_data->boundary->boundary_size += 10;
- }
- tmp_connection.protocol.http.post_data->boundary->boundary_ref[tmp_connection.protocol.http.post_data->boundary->index++] = tmp_char; /* saving boundary char */
- }
- else{
- /* final reallocation */
- uint8_t i = 0;
- char *new_tab = mem_alloc((tmp_connection.protocol.http.post_data->boundary->index+5)*sizeof(char));
- if(!new_tab){
- output_handler = &http_404_handler;
- break;
- }
- new_tab[0] = '\n';
- new_tab[1] = '\r';
- new_tab[2] = '\n';
- new_tab[3] = '-';
- new_tab[4] = '-';
- /* copying boundary */
- for(i = 0 ; i < tmp_connection.protocol.http.post_data->boundary->index ; i++)
- new_tab[i+5] = tmp_connection.protocol.http.post_data->boundary->boundary_ref[i];
- mem_free(tmp_connection.protocol.http.post_data->boundary->boundary_ref,(tmp_connection.protocol.http.post_data->boundary->boundary_size)*sizeof(char));
- tmp_connection.protocol.http.post_data->boundary->boundary_size = tmp_connection.protocol.http.post_data->boundary->index + 5;
- tmp_connection.protocol.http.post_data->boundary->boundary_ref = new_tab;
- tmp_connection.protocol.http.post_data->boundary->index = -1;
- tmp_connection.protocol.http.post_data->boundary->boundary_buffer = mem_alloc(tmp_connection.protocol.http.post_data->boundary->boundary_size*sizeof(char));
- if(!tmp_connection.protocol.http.post_data->boundary->boundary_buffer){
- /* If no space for boundary_ref, free boundary */
- mem_free(tmp_connection.protocol.http.post_data->boundary, sizeof(struct boundary_t));
- output_handler = &http_404_handler;
- break;
- }
- }
- }
- }
- /* parsing content-type */
- else if(tmp_connection.protocol.http.parsing_state == parsing_post_content_type){
- if(blob_curr - 128 == CONTENT_TYPE_MULTIPART_47_FORM_45_DATA){ /* multipart */
- /* allocating boundary structure */
- tmp_connection.protocol.http.post_data->boundary = mem_alloc(sizeof(struct boundary_t));
- if(!tmp_connection.protocol.http.post_data->boundary){
- output_handler = &http_404_handler;
- break;
- }
- tmp_connection.protocol.http.post_data->boundary->boundary_size = 10;
- tmp_connection.protocol.http.post_data->boundary->index = 0;
- tmp_connection.protocol.http.post_data->boundary->multi_part_counter = 0;
- tmp_connection.protocol.http.post_data->boundary->ready_to_count = 0;
- tmp_connection.protocol.http.post_data->boundary->boundary_ref = mem_alloc(10*sizeof(char));
- if(!tmp_connection.protocol.http.post_data->boundary->boundary_ref){
- /* If no space for boundary_ref, free boundary */
- mem_free(tmp_connection.protocol.http.post_data->boundary, sizeof(struct boundary_t));
- output_handler = &http_404_handler;
- break;
- }
- tmp_connection.protocol.http.post_data->content_type = CONTENT_TYPE_MULTIPART_47_FORM_45_DATA;
- }
- else{ /* searching content-type in application to verify it */
- tmp_connection.protocol.http.post_data->content_type = (uint8_t) -1;
- if(!output_handler->handler_mimes.mimes_size)
- tmp_connection.protocol.http.post_data->content_type = blob_curr - 128;
- else{
- uint8_t i;
- for(i = 0 ; i < output_handler->handler_mimes.mimes_size ; i++){
- if(output_handler->handler_mimes.mimes_index[i] == blob_curr - 128)
- tmp_connection.protocol.http.post_data->content_type = blob_curr - 128;
- }
- }
- if(tmp_connection.protocol.http.post_data->content_type == (uint8_t) -1){
- output_handler = &http_404_handler;
- break;
- }
- }
- tmp_connection.protocol.http.parsing_state = parsing_post_attributes;
- blob = blob_http_header_content;
- } else
-#endif
- if(tmp_connection.protocol.http.parsing_state == parsing_cmd) {
+ && output_handler != &http_505_handler
+#endif
+ ) {
+
+#if !defined(DISABLE_POST) || defined(HTTP_AUTH)
+ /* "\n\r\n\r" detected (end header or end part of multipart )*/
+ if(tmp_connection.protocol.http.parsing_state == parsing_post_end) {
+
+#ifdef HTTP_AUTH
+ /* HTTP-Auth:
+ * We are ready to send if there is no more header to parse and if
+ * requested url is not a post url.
+ */
+ if (IS_RESTRICTED (output_handler)
#ifndef DISABLE_POST
- if(blob_curr == REQUEST_POST_32_ + 128){ /* post request */
- /* allocating post data structure */
- tmp_connection.protocol.http.post_data = mem_alloc(sizeof(struct post_data_t));
- if(!tmp_connection.protocol.http.post_data){
- output_handler = &http_404_handler;
- break;
- }
- tmp_connection.protocol.http.post_data->content_type = -1;
- tmp_connection.protocol.http.post_data->content_length = -1;
- tmp_connection.protocol.http.post_data->boundary = NULL;
- tmp_connection.protocol.http.post_data->post_data = NULL;
- tmp_connection.protocol.http.post_data->filename = NULL;
- tmp_connection.protocol.http.post_data->coroutine.curr_context.status = cr_terminated;
- }
-#endif
- tmp_connection.protocol.http.parsing_state = parsing_url;
- blob = urls_tree;
- } else {
- if(tmp_char == ' ') {
+ && !tmp_connection.protocol.http.post_data
+#endif
+ ) {
+ tmp_connection.protocol.http.parsing_state = parsing_end;
+ tmp_connection.protocol.http.ready_to_send = 1;
+ break;
+ }
+#endif
+
#ifndef DISABLE_POST
- if(tmp_connection.protocol.http.post_data && tmp_connection.protocol.http.post_url_detected == 0) { /* post unauthorized */
- output_handler = &http_404_handler;
- break;
- }
- else{
-#endif
- if(!output_handler)
- output_handler = (struct output_handler_t*)CONST_ADDR(resources_index[blob_curr - 128]);
+ if(tmp_connection.protocol.http.post_data->content_type == (uint8_t)-1) { /* no content type */
+ output_handler = &http_505_handler;
+ break;
+ }
+
+ if(tmp_connection.protocol.http.post_data->boundary){
+ tmp_connection.protocol.http.post_data->boundary->ready_to_count = 1;
+ /* parsing header part of multipart */
+ if(tmp_connection.protocol.http.post_data->content_type == CONTENT_TYPE_MULTIPART_47_FORM_45_DATA){
+ tmp_connection.protocol.http.parsing_state = parsing_post_attributes;
+ blob = blob_http_header_content;
+ continue;
+ }
+ else
+ /* parsing data */
+ tmp_connection.protocol.http.parsing_state = parsing_post_data;
+ }
+ /* parsing form */
+ else if(tmp_connection.protocol.http.post_data->content_type == CONTENT_TYPE_APPLICATION_47_X_45_WWW_45_FORM_45_URLENCODED)
+ tmp_connection.protocol.http.parsing_state = parsing_post_args;
+ else{
+ /* no content length detected = boundary is "\r\n\r\n" */
+ if(tmp_connection.protocol.http.post_data->content_length == (uint16_t)-1){
+ tmp_connection.protocol.http.post_data->boundary = mem_alloc(sizeof(struct boundary_t));
+ if(!tmp_connection.protocol.http.post_data->boundary){
+ output_handler = &http_404_handler;
+ break;
+ }
+ tmp_connection.protocol.http.post_data->boundary->boundary_size = 4;
+ tmp_connection.protocol.http.post_data->boundary->index = -1;
+ tmp_connection.protocol.http.post_data->boundary->multi_part_counter = 0;
+ tmp_connection.protocol.http.post_data->boundary->boundary_ref = "\r\n\r\n";
+ tmp_connection.protocol.http.post_data->boundary->boundary_buffer = mem_alloc(4*sizeof(char));
+ if(!tmp_connection.protocol.http.post_data->boundary->boundary_buffer){
+ /* If boundary buffer can not be allocated, also free the boundary itself */
+ mem_free(tmp_connection.protocol.http.post_data->boundary, sizeof(struct boundary_t));
+ output_handler = &http_404_handler;
+ break;
+ }
+ }
+ tmp_connection.protocol.http.parsing_state = parsing_post_data;
+ }
+#endif
+#endif
+#if !defined(DISABLE_POST) || defined(HTTP_AUTH)
+ }
+#endif
#ifndef DISABLE_POST
- if(tmp_connection.protocol.http.post_data){
- tmp_connection.protocol.http.parsing_state = parsing_post_attributes;
- blob = blob_http_header_content;
- tmp_connection.protocol.http.ready_to_send = 0;
- }
- else{
-#endif
- tmp_connection.protocol.http.parsing_state = parsing_end;
- break;
+ /* parsing post data => run coroutine */
+ if(tmp_connection.protocol.http.parsing_state == parsing_post_data){
+ /* starting buffer init */
+ if(tmp_connection.protocol.http.post_data->coroutine.curr_context.status == cr_terminated
+ && tmp_connection.protocol.http.post_data->boundary
+ && tmp_connection.protocol.http.post_data->boundary->index == 255){
+ tmp_connection.protocol.http.post_data->boundary->index = 0;
+ tmp_connection.protocol.http.parsing_state = parsing_init_buffer;
+ continue;
+ }
+ uint16_t length_temp = segment_length - x;
+ /* initialization coroutine */
+ if(tmp_connection.protocol.http.post_data->coroutine.curr_context.status == cr_terminated){
+ cr_init(&(tmp_connection.protocol.http.post_data->coroutine));
+ tmp_connection.protocol.http.post_data->coroutine.func.func_post_in = CONST_ADDR(GET_GENERATOR(output_handler).handlers.post.dopostin);
+ tmp_connection.protocol.http.post_data->coroutine.params.in.content_type = tmp_connection.protocol.http.post_data->content_type;
+ tmp_connection.protocol.http.post_data->coroutine.params.in.filename = tmp_connection.protocol.http.post_data->filename;
+ tmp_connection.protocol.http.post_data->coroutine.params.in.post_data = tmp_connection.protocol.http.post_data->post_data;
+ if(tmp_connection.protocol.http.post_data->boundary){
+ tmp_connection.protocol.http.post_data->coroutine.params.in.part_number = tmp_connection.protocol.http.post_data->boundary->multi_part_counter;
+ tmp_connection.protocol.http.post_data->boundary->index = 0;
+ }
+ else
+ tmp_connection.protocol.http.post_data->coroutine.params.in.part_number = 0;
+ if(cr_prepare(&(tmp_connection.protocol.http.post_data->coroutine)) == NULL)
+ {
+ /* TODO: shoudn't the boundary and boundary_buffer be free ? */
+ return 1;
+ }
+ }
+ curr_input.length = length_temp;
+ curr_input.connection = &tmp_connection;
+ coroutine_state.state = cor_in;
+ /* running coroutine */
+ cr_run(&(tmp_connection.protocol.http.post_data->coroutine),cor_type_post_in);
+ coroutine_state.state = cor_out;
+ x += (length_temp-curr_input.length);
+ if(tmp_connection.protocol.http.post_data->coroutine.curr_context.status == cr_terminated){ /* if is terminated */
+ tmp_connection.protocol.http.post_data->post_data = tmp_connection.protocol.http.post_data->coroutine.params.in.post_data;
+ cr_clean(&(tmp_connection.protocol.http.post_data->coroutine));
+ /* cleaning filename memory */
+ if(tmp_connection.protocol.http.post_data->filename){
+ uint8_t i = 0;
+ while(tmp_connection.protocol.http.post_data->filename[i++] != '\0');
+ mem_free(tmp_connection.protocol.http.post_data->filename,i*sizeof(char));
+ tmp_connection.protocol.http.post_data->filename = NULL;
+ }
+ /* if no boundary, there is no data to parse */
+ if(!tmp_connection.protocol.http.post_data->boundary){
+ tmp_connection.protocol.http.parsing_state = parsing_end;
+ tmp_connection.protocol.http.ready_to_send = 1;
+ }
+ else{
+ /* starting search of boundary if no found, or ready for next part */
+ tmp_connection.protocol.http.post_data->boundary->multi_part_counter++;
+ if(tmp_connection.protocol.http.post_data->boundary->index != (uint8_t)-1)
+ tmp_connection.protocol.http.parsing_state = parsing_boundary;
+ else{
+ tmp_connection.protocol.http.parsing_state = parsing_post_attributes;
+ blob = blob_http_header_content;
+ }
+ /* if no content length, parsing is terminated */
+ if(tmp_connection.protocol.http.post_data->content_length == (uint16_t)-1){
+ tmp_connection.protocol.http.parsing_state = parsing_end;
+ tmp_connection.protocol.http.ready_to_send = 1;
+ break;
+ }
+ }
+ }
+ if(tmp_connection.protocol.http.post_data->boundary)
+ continue;
+ break;
+ }
+
+ /* searching end character of post url detection */
+ if(tmp_connection.protocol.http.parsing_state == parsing_url && blob_curr == URL_POST_END){
+ if(tmp_connection.protocol.http.post_data){
+ tmp_connection.protocol.http.post_url_detected = 1;
+ blob_curr = CONST_READ_UI8(++blob);
+ }
+ else{ /* get unauthorized */
+ output_handler = &http_404_handler;
+ break;
+ }
+ }
+#endif
+
+#if defined(HTTP_AUTH) && HTTP_AUTH == HTTP_AUTH_DIGEST
+ if (tmp_connection.protocol.http.parsing_state == parsing_authorization_username) {
+ if (blob_curr >= 128) {
+ /* Username has been successfully parsed. */
+ auth_data.username_blob = blob_curr;
+ blob = blob_http_header_content;
+ tmp_connection.protocol.http.parsing_state = parsing_post_attributes;
+ continue; /* Skip the final '"' */
+ }
+ else {
+ /* Error: invalid username */
+ tmp_connection.protocol.http.blob = (unsigned char *)(output_handler);
+ output_handler = &http_401_handler;
+ tmp_connection.protocol.http.parsing_state = parsing_end;
+ break;
+ }
+ }
+#endif
+
+#if !defined(DISABLE_POST) || defined(HTTP_AUTH)
+ /* parsing attributes of post header */
+ if(tmp_connection.protocol.http.parsing_state == parsing_post_attributes) {
+#endif
+
+#ifdef HTTP_AUTH
+ if (blob_curr == ATTRIBUT_AUTHORIZATION_58_ + 128) {
+
+ if (!auth_data.scheme_parsed) {
+ if (IS_LWS_CHAR (tmp_char)) {
+ /* Parsing did not start yet (escape unsignificant whitespaces) */
+ if (auth_data.parsing_offset == NO_OFFSET)
+ continue;
+
+ /* Parsing just ended */
+ if (HttpAuthenticateScheme[auth_data.parsing_offset] == '\0') {
+ auth_data.scheme_parsed = 1;
+ auth_data.parsing_offset = NO_OFFSET;
+ continue;
+ }
+ }
+ else {
+ /* Parsing just started */
+ if (auth_data.parsing_offset == NO_OFFSET)
+ auth_data.parsing_offset = 0;
+
+ if (LOWER_CASE (tmp_char)
+ == HttpAuthenticateScheme[auth_data.parsing_offset]) {
+ ++auth_data.parsing_offset;
+ continue;
+ }
+ }
+
+ /* If execution flow reach this point, scheme parsing failed. */
+ tmp_connection.protocol.http.blob = (unsigned char *)(output_handler);
+ output_handler = &http_401_handler;
+ auth_data.parsing_offset = NO_OFFSET;
+ tmp_connection.protocol.http.parsing_state = parsing_end;
+ break;
+ }
+ else {
+#if HTTP_AUTH == HTTP_AUTH_BASIC
+ /* If no space has been allocated to store given credentials,
+ * allocate it ! */
+ if (!auth_data.credentials) {
+ auth_data.credentials = mem_alloc(10 * sizeof(char));
+ if (!auth_data.credentials) {
+ output_handler = &http_404_handler;
+ break;
+ }
+
+ auth_data.credentials[0] = 2; /* First byte is the used space */
+ auth_data.credentials[1] = 10; /* Second byte is the allocated space */
+ }
+
+ /* Escape unsignificant whitespace */
+ if (IS_LWS_CHAR(tmp_char) && auth_data.credentials[0] == 2)
+ continue;
+
+ /* As long as the character read is a base64 character, fill
+ * credentials string */
+ if (IS_B64_CHAR (tmp_char)) {
+ /* String container reallocation if needed */
+ if (auth_data.credentials[0] == auth_data.credentials[1]) {
+ auth_data.credentials = mem_realloc(auth_data.credentials,
+ auth_data.credentials[0],
+ 10);
+ if (!auth_data.credentials) {
+ output_handler = &http_404_handler;
+ break;
+ }
+
+ auth_data.credentials[1] += 10;
+ }
+
+ /* Add current character */
+ auth_data.credentials[auth_data.credentials[0]++] = tmp_char;
+ }
+ else {
+ uint8_t i = 0;
+ unsigned char *final_credentials;
+
+ final_credentials = mem_alloc((auth_data.credentials[0] - 1)
+ * sizeof (unsigned char));
+ if (!final_credentials) {
+ output_handler = &http_404_handler;
+ break;
+ }
+
+ /* Copy credentials string into final buffer */
+ for (i = 0; i < auth_data.credentials[0] - 2; ++i)
+ final_credentials[i] = auth_data.credentials[i + 2];
+ final_credentials[i] = '\0';
+
+ mem_free (auth_data.credentials,
+ auth_data.credentials[1] * sizeof (unsigned char));
+
+ auth_data.credentials = final_credentials;
+ tmp_connection.protocol.http.parsing_state = parsing_post_attributes;
+ blob = blob_http_header_content;
+ }
+#elif HTTP_AUTH == HTTP_AUTH_DIGEST
+ blob = blob_http_header_content;
+#endif
+ }
+ }
+#if HTTP_AUTH == HTTP_AUTH_DIGEST
+ else if (blob_curr == ATTRIBUT_USERNAME_61_ + 128) {
+ blob = usernames_tree;
+ tmp_connection.protocol.http.parsing_state = parsing_authorization_username;
+ continue; /* Skip the current '"' */
+ }
+ else if (blob_curr == ATTRIBUT_NONCE_61_ + 128) {
+
+ if (tmp_char == '"') {
+ switch (auth_data.parsing_offset) {
+ /* Parsing just started: set offset and skip the double quote */
+ case NO_OFFSET:
+ auth_data.parsing_offset = 0;
+ continue;
+
+ /* Parsing just ended: reset offset and skip the double quote */
+ case NONCE_LEN:
+ auth_data.parsing_offset = NO_OFFSET;
+ blob = blob_http_header_content;
+ continue;
+
+ /* Error: nonce value doesn't have a valid length */
+ default:
+ tmp_connection.protocol.http.blob = (unsigned char *)(output_handler);
+ output_handler = &http_401_handler;
+ auth_data.parsing_offset = NO_OFFSET;
+ break;
+ }
+ }
+ else {
+ switch (auth_data.parsing_offset) {
+ /* Parsing didn't start yet, but tmp_char is not a double quote */
+ case NO_OFFSET: // WARNING: Fall through
+ /* Parsed string has a length > NONCE_LEN */
+ case NONCE_LEN:
+ tmp_connection.protocol.http.blob = (unsigned char *)(output_handler);
+ output_handler = &http_401_handler;
+ auth_data.parsing_offset = NO_OFFSET;
+ tmp_connection.protocol.http.ready_to_send = 1;
+ break;
+
+ default:
+ auth_data.nonce[auth_data.parsing_offset++] = tmp_char;
+ break;
+ }
+ }
+ }
+ else if (blob_curr == ATTRIBUT_RESPONSE_61_ + 128) {
+
+ if (tmp_char == '"') {
+ switch (auth_data.parsing_offset) {
+ /* Parsing just started: set offset and skip the double quote */
+ case NO_OFFSET:
+ auth_data.parsing_offset = 0;
+ continue;
+
+ /* Parsing just ended: reset offset and skip the double quote */
+ case MD5_DIGEST_LEN:
+ auth_data.parsing_offset = NO_OFFSET;
+ blob = blob_http_header_content;
+ continue;
+
+ /* Error: response value doesn't have a valid length */
+ default:
+ auth_data.parsing_offset = NO_OFFSET;
+ tmp_connection.protocol.http.blob = (unsigned char *)(output_handler);
+ output_handler = &http_401_handler;
+ break;
+ }
+ }
+ else {
+ switch (auth_data.parsing_offset) {
+ /* Parsing didn't start yet, but tmp_char is not a double quote */
+ case NO_OFFSET: // WARNING: Fall through
+ /* Parsed string has a length > NONCE_LEN */
+ case MD5_DIGEST_LEN:
+ auth_data.parsing_offset = NO_OFFSET;
+ tmp_connection.protocol.http.blob = (unsigned char *)(output_handler);
+ output_handler = &http_401_handler;
+ break;
+
+ default:
+ auth_data.response[auth_data.parsing_offset++] = tmp_char;
+ break;
+ }
+ }
+ }
+#endif
+
#ifndef DISABLE_POST
- }
- }
+ else
#endif
- } else {
-#ifndef DISABLE_ARGS
- if(tmp_char == '?'
+#endif
+
#ifndef DISABLE_POST
- || (tmp_connection.protocol.http.parsing_state == parsing_post_args && tmp_char == 10)
-#endif
- ){
- uint16_t tmp_args_size;
- if(!output_handler)
- output_handler = (struct output_handler_t*)CONST_ADDR(resources_index[blob_curr - 128]);
- tmp_args_size = CONST_UI16(output_handler->handler_args.args_size);
- tmp_args_size_ref = tmp_args_size;
- tmp_connection.protocol.http.ready_to_send = 0;
- if(tmp_args_size) {
- uint16_t i;
- blob = (const unsigned char *)CONST_ADDR(output_handler->handler_args.args_tree);
- tmp_connection.protocol.http.args = mem_alloc(tmp_args_size); /* test NULL: done */
- if(tmp_connection.protocol.http.args == NULL) {
- output_handler = &http_404_handler;
- break;
- }
- for(i =0 ; i < tmp_args_size ; ++i) {
- ((unsigned char *)tmp_connection.protocol.http.args)[i] = 0;
- }
- continue;
- }
- } else if(tmp_char == '=' && tmp_connection.protocol.http.args) {
- struct arg_ref_t * /*CONST_VAR*/ tmp_arg_ref_ptr;
- tmp_connection.protocol.http.arg_ref_index = blob_curr - 128;
- tmp_arg_ref_ptr = &(((struct arg_ref_t*)CONST_ADDR(output_handler->handler_args.args_index))[tmp_connection.protocol.http.arg_ref_index]);
- tmp_arg_ref.arg_type = CONST_UI8(tmp_arg_ref_ptr->arg_type);
- tmp_arg_ref.arg_size = CONST_UI8(tmp_arg_ref_ptr->arg_size);
- tmp_arg_ref.arg_offset = CONST_UI8(tmp_arg_ref_ptr->arg_offset);
- tmp_connection.protocol.http.curr_arg = ((unsigned char*)tmp_connection.protocol.http.args) + tmp_arg_ref.arg_offset;
- if(tmp_arg_ref.arg_type == arg_str)
- (*((unsigned char*)tmp_connection.protocol.http.curr_arg + tmp_arg_ref.arg_size - 1)) = tmp_arg_ref.arg_size - 1;
- continue;
- } else if(tmp_char == '&') {
- blob = (const unsigned char *)CONST_ADDR(output_handler->handler_args.args_tree);
- } else {
- blob++;
- }
-#else
- blob++;
+ if(blob_curr == ATTRIBUT_CONTENT_45_TYPE + 128) { /* content-type */
+ blob = mimes_tree;
+ tmp_connection.protocol.http.parsing_state = parsing_post_content_type;
+ }
+ else if(blob_curr == ATTRIBUT_CONTENT_45_LENGTH + 128){ /* content-length */
+ if(tmp_connection.protocol.http.post_data->content_length == (uint8_t)-1)
+ tmp_connection.protocol.http.post_data->content_length = 0;
+ if(tmp_char != ' ' && tmp_char != '\r'){
+ tmp_connection.protocol.http.post_data->content_length *= 10;
+ tmp_connection.protocol.http.post_data->content_length += tmp_char - '0';
+ }
+ }
+ else if(blob_curr == ATTRIBUT_FILENAME_61_ + 128){ /* filename */
+ if(!tmp_connection.protocol.http.post_data->filename){
+ tmp_connection.protocol.http.post_data->filename = mem_alloc(10 * sizeof(char));
+ if(!tmp_connection.protocol.http.post_data->filename){
+ output_handler = &http_404_handler;
+ break;
+ }
+ tmp_connection.protocol.http.post_data->filename[0] = 2; /* first value is the size of filename */
+ tmp_connection.protocol.http.post_data->filename[1] = 10; /* second value is the size allocated */
+ }
+ else if(tmp_char == '\"'){ /* end of filename, the indexes are removed */
+ uint8_t i = 0;
+ char *new_tab = mem_alloc((tmp_connection.protocol.http.post_data->filename[0]-1)*sizeof(char));
+ if(!new_tab){
+ output_handler = &http_404_handler;
+ break;
+ }
+ for(i = 0 ; i < tmp_connection.protocol.http.post_data->filename[0]-2 ; i++)
+ new_tab[i] = tmp_connection.protocol.http.post_data->filename[i+2];
+ new_tab[i]='\0';
+ mem_free(tmp_connection.protocol.http.post_data->filename,(tmp_connection.protocol.http.post_data->filename[1])*sizeof(char));
+ tmp_connection.protocol.http.post_data->filename = new_tab;
+ tmp_connection.protocol.http.parsing_state = parsing_post_attributes;
+ blob = blob_http_header_content;
+ }
+ else{
+ /* reallocating filename */
+ if(tmp_connection.protocol.http.post_data->filename[0] == tmp_connection.protocol.http.post_data->filename[1]){
+ tmp_connection.protocol.http.post_data->filename = mem_realloc(tmp_connection.protocol.http.post_data->filename,tmp_connection.protocol.http.post_data->filename[1],10);
+ if(!tmp_connection.protocol.http.post_data->filename){
+ output_handler = &http_404_handler;
+ break;
+ }
+ /* updating size */
+ tmp_connection.protocol.http.post_data->filename[1] = tmp_connection.protocol.http.post_data->filename[1] + 10;
+ }
+ /* add current character */
+ tmp_connection.protocol.http.post_data->filename[tmp_connection.protocol.http.post_data->filename[0]] = tmp_char;
+ tmp_connection.protocol.http.post_data->filename[0]++;
+ }
+ }
+ /* parsing boundary */
+ else if(blob_curr == ATTRIBUT_BOUNDARY_61_ + 128){
+ if(tmp_char != '\r'){
+ /* reallocating tab */
+ if(tmp_connection.protocol.http.post_data->boundary->index == tmp_connection.protocol.http.post_data->boundary->boundary_size){
+ tmp_connection.protocol.http.post_data->boundary->boundary_ref = mem_realloc(tmp_connection.protocol.http.post_data->boundary->boundary_ref,tmp_connection.protocol.http.post_data->boundary->boundary_size,10);
+ if(!tmp_connection.protocol.http.post_data->boundary->boundary_ref){
+ output_handler = &http_404_handler;
+ break;
+ }
+ /* updating size */
+ tmp_connection.protocol.http.post_data->boundary->boundary_size += 10;
+ }
+ tmp_connection.protocol.http.post_data->boundary->boundary_ref[tmp_connection.protocol.http.post_data->boundary->index++] = tmp_char; /* saving boundary char */
+ }
+ else{
+ /* final reallocation */
+ uint8_t i = 0;
+ char *new_tab = mem_alloc((tmp_connection.protocol.http.post_data->boundary->index+5)*sizeof(char));
+ if(!new_tab){
+ output_handler = &http_404_handler;
+ break;
+ }
+ new_tab[0] = '\n';
+ new_tab[1] = '\r';
+ new_tab[2] = '\n';
+ new_tab[3] = '-';
+ new_tab[4] = '-';
+ /* copying boundary */
+ for(i = 0 ; i < tmp_connection.protocol.http.post_data->boundary->index ; i++)
+ new_tab[i+5] = tmp_connection.protocol.http.post_data->boundary->boundary_ref[i];
+ mem_free(tmp_connection.protocol.http.post_data->boundary->boundary_ref,(tmp_connection.protocol.http.post_data->boundary->boundary_size)*sizeof(char));
+ tmp_connection.protocol.http.post_data->boundary->boundary_size = tmp_connection.protocol.http.post_data->boundary->index + 5;
+ tmp_connection.protocol.http.post_data->boundary->boundary_ref = new_tab;
+ tmp_connection.protocol.http.post_data->boundary->index = -1;
+ tmp_connection.protocol.http.post_data->boundary->boundary_buffer = mem_alloc(tmp_connection.protocol.http.post_data->boundary->boundary_size*sizeof(char));
+ if(!tmp_connection.protocol.http.post_data->boundary->boundary_buffer){
+ /* If no space for boundary_ref, free boundary */
+ mem_free(tmp_connection.protocol.http.post_data->boundary, sizeof(struct boundary_t));
+ output_handler = &http_404_handler;
+ break;
+ }
+ }
+ }
+#endif
+#if !defined(DISABLE_POST) || defined(HTTP_AUTH)
+ }
#endif
- }
- }
- blob_curr = CONST_READ_UI8(blob);
- }
#ifndef DISABLE_POST
- /* end header detection */
- if(tmp_connection.protocol.http.parsing_state == parsing_post_attributes && tmp_char == 13){
- blob = blob_http_header_end;
- tmp_connection.protocol.http.parsing_state = parsing_post_end;
- }
- else if(tmp_connection.protocol.http.parsing_state == parsing_post_end){
- if(tmp_char != blob_curr){
- blob = blob_http_header_content;
- tmp_connection.protocol.http.parsing_state = parsing_post_attributes;
- }
- }
+ /* parsing content-type */
+ else if(tmp_connection.protocol.http.parsing_state == parsing_post_content_type){
+ if(blob_curr - 128 == CONTENT_TYPE_MULTIPART_47_FORM_45_DATA){ /* multipart */
+ /* allocating boundary structure */
+ tmp_connection.protocol.http.post_data->boundary = mem_alloc(sizeof(struct boundary_t));
+ if(!tmp_connection.protocol.http.post_data->boundary){
+ output_handler = &http_404_handler;
+ break;
+ }
+ tmp_connection.protocol.http.post_data->boundary->boundary_size = 10;
+ tmp_connection.protocol.http.post_data->boundary->index = 0;
+ tmp_connection.protocol.http.post_data->boundary->multi_part_counter = 0;
+ tmp_connection.protocol.http.post_data->boundary->ready_to_count = 0;
+ tmp_connection.protocol.http.post_data->boundary->boundary_ref = mem_alloc(10*sizeof(char));
+ if(!tmp_connection.protocol.http.post_data->boundary->boundary_ref){
+ /* If no space for boundary_ref, free boundary */
+ mem_free(tmp_connection.protocol.http.post_data->boundary, sizeof(struct boundary_t));
+ output_handler = &http_404_handler;
+ break;
+ }
+ tmp_connection.protocol.http.post_data->content_type = CONTENT_TYPE_MULTIPART_47_FORM_45_DATA;
+ }
+ else{ /* searching content-type in application to verify it */
+ tmp_connection.protocol.http.post_data->content_type = (uint8_t) -1;
+ if(!output_handler->handler_mimes.mimes_size)
+ tmp_connection.protocol.http.post_data->content_type = blob_curr - 128;
+ else{
+ uint8_t i;
+ for(i = 0 ; i < output_handler->handler_mimes.mimes_size ; i++){
+ if(output_handler->handler_mimes.mimes_index[i] == blob_curr - 128)
+ tmp_connection.protocol.http.post_data->content_type = blob_curr - 128;
+ }
+ }
+ if(tmp_connection.protocol.http.post_data->content_type == (uint8_t) -1){
+ output_handler = &http_404_handler;
+ break;
+ }
+ }
+ tmp_connection.protocol.http.parsing_state = parsing_post_attributes;
+ blob = blob_http_header_content;
+ }
#endif
-#ifndef DISABLE_ARGS
- if(tmp_connection.protocol.http.arg_ref_index != 128) {
- if(tmp_char == '&') {
- tmp_connection.protocol.http.arg_ref_index = 128;
- blob = (const unsigned char *)CONST_ADDR(output_handler->handler_args.args_tree);
- continue;
- } else if(tmp_char == ' ') {
- tmp_connection.protocol.http.ready_to_send = 1;
- tmp_connection.protocol.http.parsing_state = parsing_end;
- break;
- } else {
- switch(tmp_arg_ref.arg_type) {
- case arg_str: {
- unsigned char *tmp_size_ptr = ((unsigned char*)tmp_connection.protocol.http.curr_arg + tmp_arg_ref.arg_size - 1);
- if(*tmp_size_ptr) {
- *((unsigned char*)tmp_connection.protocol.http.curr_arg + (tmp_arg_ref.arg_size - *tmp_size_ptr - 1)) = tmp_char;
- (*tmp_size_ptr)--;
- }
- break;
- }
- case arg_ui8:
- *((unsigned char*)tmp_connection.protocol.http.curr_arg) *= 10;
- *((unsigned char*)tmp_connection.protocol.http.curr_arg) += tmp_char - '0';
- break;
- case arg_ui16:
- *((uint16_t*)tmp_connection.protocol.http.curr_arg) *= 10;
- *((uint16_t*)tmp_connection.protocol.http.curr_arg) += tmp_char - '0';
- break;
- }
- }
- } else
+#if !defined(DISABLE_POST) || defined(HTTP_AUTH)
+ else
#endif
+
+ if(tmp_connection.protocol.http.parsing_state == parsing_cmd) {
+#ifndef DISABLE_POST
+ if(blob_curr == REQUEST_POST_32_ + 128) { /* post request */
+ /* allocating post data structure */
+ tmp_connection.protocol.http.post_data = mem_alloc(sizeof(struct post_data_t));
+ if(!tmp_connection.protocol.http.post_data){
+ output_handler = &http_404_handler;
+ break;
+ }
+ tmp_connection.protocol.http.post_data->content_type = -1;
+ tmp_connection.protocol.http.post_data->content_length = -1;
+ tmp_connection.protocol.http.post_data->boundary = NULL;
+ tmp_connection.protocol.http.post_data->post_data = NULL;
+ tmp_connection.protocol.http.post_data->filename = NULL;
+ tmp_connection.protocol.http.post_data->coroutine.curr_context.status = cr_terminated;
+ }
+#endif
+ tmp_connection.protocol.http.parsing_state = parsing_url;
+ blob = urls_tree;
+ } else {
+ if(tmp_char == ' ') {
#ifndef DISABLE_POST
- if(tmp_connection.protocol.http.parsing_state == parsing_post_end && blob_curr != HEADER_POST_END){
- blob++;
- }
- else if(
- !(tmp_connection.protocol.http.parsing_state == parsing_post_content_type && (tmp_char == 32 || tmp_char == 58))
- && !(tmp_connection.protocol.http.parsing_state == parsing_post_attributes && blob_curr == ATTRIBUT_CONTENT_45_LENGTH + 128)
- && !(tmp_connection.protocol.http.parsing_state == parsing_post_attributes && blob_curr == ATTRIBUT_BOUNDARY_61_ + 128)
- && !(tmp_connection.protocol.http.parsing_state == parsing_post_attributes && blob_curr == ATTRIBUT_FILENAME_61_ + 128)
- )
-#endif
- {
- do {
-
- unsigned char offsetInf = 0;
- unsigned char offsetEq = 0;
- unsigned char blob_next;
+ if(tmp_connection.protocol.http.post_data && tmp_connection.protocol.http.post_url_detected == 0) { /* post unauthorized */
+ output_handler = &http_404_handler;
+ break;
+ }
+ else{
+#endif
+ if(!output_handler) {
+ output_handler = (struct output_handler_t*)CONST_ADDR(resources_index[blob_curr - 128]);
+ tmp_blob = blob_curr - 128;
+ }
+
+#if !defined(DISABLE_POST) || defined(HTTP_AUTH)
+ if (
#ifndef DISABLE_POST
- if(tmp_connection.protocol.http.parsing_state == parsing_post_attributes && tmp_char < 123 && tmp_char > 96)
- tmp_char = tmp_char - 'a' + 'A';
-#endif
- blob_curr = CONST_READ_UI8(blob);
- blob_next = CONST_READ_UI8(++blob);
- if (tmp_char != blob_curr && blob_next >= 128) {
- blob_next = CONST_READ_UI8(++blob);
- }
- if (blob_next < 32) {
- offsetInf += ((blob_next>>2) & 1) + ((blob_next>>1) & 1) + (blob_next & 1);
- offsetEq = offsetInf + ((blob_next & 2)?CONST_READ_UI8(blob+1):0);
- }
- if (tmp_char == blob_curr) {
- if (blob_next < 32) {
- if (blob_next & 2) {
- blob += offsetEq;
- } else {
+ tmp_connection.protocol.http.post_data
+#endif
+#if !defined(DISABLE_POST) && defined(HTTP_AUTH)
+ ||
+#endif
+#ifdef HTTP_AUTH
+ IS_RESTRICTED(output_handler)
+#endif
+ ) {
+ tmp_connection.protocol.http.parsing_state = parsing_post_attributes;
+ blob = blob_http_header_content;
+ tmp_connection.protocol.http.ready_to_send = 0;
+ }
+ else {
+#endif
+ tmp_connection.protocol.http.parsing_state = parsing_end;
+ break;
+#if !defined(DISABLE_POST) || defined(HTTP_AUTH)
+ }
+#endif
+#ifndef DISABLE_POST
+ }
+#endif
+ } else {
+
+#ifndef DISABLE_ARGS
+ if(tmp_char == '?'
#ifndef DISABLE_POST
- if(tmp_connection.protocol.http.parsing_state == parsing_post_attributes)
- blob = blob_http_header_content;
- else
-#endif
- output_handler = &http_404_handler;
- break;
- }
- }
- break;
- } else if (tmp_char < blob_curr) {
- if (blob_next < 32 && blob_next & 1) {
- blob += offsetInf;
- } else {
+ || (tmp_connection.protocol.http.parsing_state == parsing_post_args && tmp_char == 10)
+#endif
+ ){
+ uint16_t tmp_args_size;
+ if(!output_handler) {
+ output_handler = (struct output_handler_t*)CONST_ADDR(resources_index[blob_curr - 128]);
+ tmp_blob = blob_curr - 128;
+ }
+ tmp_args_size = CONST_UI16(output_handler->handler_args.args_size);
+ tmp_args_size_ref = tmp_args_size;
+ tmp_connection.protocol.http.ready_to_send = 0;
+ if(tmp_args_size) {
+ uint16_t i;
+ blob = (const unsigned char *)CONST_ADDR(output_handler->handler_args.args_tree);
+ tmp_connection.protocol.http.args = mem_alloc(tmp_args_size); /* test NULL: done */
+ if(tmp_connection.protocol.http.args == NULL) {
+ output_handler = &http_404_handler;
+ break;
+ }
+ for(i =0 ; i < tmp_args_size ; ++i) {
+ ((unsigned char *)tmp_connection.protocol.http.args)[i] = 0;
+ }
+ continue;
+ }
+ } else if(tmp_char == '=' && tmp_connection.protocol.http.args) {
+ struct arg_ref_t * /*CONST_VAR*/ tmp_arg_ref_ptr;
+ tmp_connection.protocol.http.arg_ref_index = blob_curr - 128;
+ tmp_arg_ref_ptr = &(((struct arg_ref_t*)CONST_ADDR(output_handler->handler_args.args_index))[tmp_connection.protocol.http.arg_ref_index]);
+ tmp_arg_ref.arg_type = CONST_UI8(tmp_arg_ref_ptr->arg_type);
+ tmp_arg_ref.arg_size = CONST_UI8(tmp_arg_ref_ptr->arg_size);
+ tmp_arg_ref.arg_offset = CONST_UI8(tmp_arg_ref_ptr->arg_offset);
+ tmp_connection.protocol.http.curr_arg = ((unsigned char*)tmp_connection.protocol.http.args) + tmp_arg_ref.arg_offset;
+ if(tmp_arg_ref.arg_type == arg_str)
+ (*((unsigned char*)tmp_connection.protocol.http.curr_arg + tmp_arg_ref.arg_size - 1)) = tmp_arg_ref.arg_size - 1;
+ continue;
+ } else if(tmp_char == '&') {
+ blob = (const unsigned char *)CONST_ADDR(output_handler->handler_args.args_tree);
+ } else {
+ blob++;
+ }
+#else
+ blob++;
+#endif
+ }
+ }
+ blob_curr = CONST_READ_UI8(blob);
+ }
+
+#if !defined(DISABLE_POST) || defined(HTTP_AUTH)
+ /* end header detection */
+ if(tmp_connection.protocol.http.parsing_state == parsing_post_attributes && tmp_char == 13){
+ blob = blob_http_header_end;
+ tmp_connection.protocol.http.parsing_state = parsing_post_end;
+ }
+ else if(tmp_connection.protocol.http.parsing_state == parsing_post_end){
+ if(tmp_char != blob_curr){
+ blob = blob_http_header_content;
+ tmp_connection.protocol.http.parsing_state = parsing_post_attributes;
+ }
+ }
+#endif
+#ifndef DISABLE_ARGS
+ if(tmp_connection.protocol.http.arg_ref_index != 128) {
+ if(tmp_char == '&') {
+ tmp_connection.protocol.http.arg_ref_index = 128;
+ blob = (const unsigned char *)CONST_ADDR(output_handler->handler_args.args_tree);
+ continue;
+ }
+ else if(tmp_char == ' ') {
+ tmp_connection.protocol.http.ready_to_send = 1;
+ tmp_connection.protocol.http.parsing_state = parsing_end;
+ break;
+ }
+ else {
+ switch(tmp_arg_ref.arg_type) {
+ case arg_str: {
+ unsigned char *tmp_size_ptr = ((unsigned char*)tmp_connection.protocol.http.curr_arg + tmp_arg_ref.arg_size - 1);
+ if(*tmp_size_ptr) {
+ *((unsigned char*)tmp_connection.protocol.http.curr_arg + (tmp_arg_ref.arg_size - *tmp_size_ptr - 1)) = tmp_char;
+ (*tmp_size_ptr)--;
+ }
+ break;
+ }
+ case arg_ui8:
+ *((unsigned char*)tmp_connection.protocol.http.curr_arg) *= 10;
+ *((unsigned char*)tmp_connection.protocol.http.curr_arg) += tmp_char - '0';
+ break;
+ case arg_ui16:
+ *((uint16_t*)tmp_connection.protocol.http.curr_arg) *= 10;
+ *((uint16_t*)tmp_connection.protocol.http.curr_arg) += tmp_char - '0';
+ break;
+ }
+ }
+ } else
+#endif
+#if !defined(DISABLE_POST) || defined(HTTP_AUTH)
+ if(tmp_connection.protocol.http.parsing_state == parsing_post_end && blob_curr != HEADER_POST_END){
+ blob++;
+ }
+ else if (
#ifndef DISABLE_POST
- if(tmp_connection.protocol.http.parsing_state == parsing_post_attributes)
- blob = blob_http_header_content;
- else
-#endif
- output_handler = &http_404_handler;
- break;
- }
- } else {
- if (blob_next < 32 && blob_next & 4) {
- unsigned char offsetSup = offsetEq + ((blob_next & 3)?CONST_READ_UI8(blob+(offsetInf-1)):0);
- blob += offsetSup;
- } else {
+ !(tmp_connection.protocol.http.parsing_state == parsing_post_content_type && (tmp_char == 32 || tmp_char == 58))
+ && !(tmp_connection.protocol.http.parsing_state == parsing_post_attributes && blob_curr == ATTRIBUT_CONTENT_45_LENGTH + 128)
+ && !(tmp_connection.protocol.http.parsing_state == parsing_post_attributes && blob_curr == ATTRIBUT_BOUNDARY_61_ + 128)
+ && !(tmp_connection.protocol.http.parsing_state == parsing_post_attributes && blob_curr == ATTRIBUT_FILENAME_61_ + 128)
+#endif
+#if !defined(DISABLE_POST) && defined(HTTP_AUTH)
+ &&
+#endif
+#ifdef HTTP_AUTH
+ !(tmp_connection.protocol.http.parsing_state == parsing_post_attributes && blob_curr == ATTRIBUT_AUTHORIZATION_58_ + 128)
+#if HTTP_AUTH == HTTP_AUTH_DIGEST
+ && !(tmp_connection.protocol.http.parsing_state == parsing_post_attributes && blob_curr == ATTRIBUT_USERNAME_61_ + 128)
+ && !(tmp_connection.protocol.http.parsing_state == parsing_post_attributes && blob_curr == ATTRIBUT_NONCE_61_ + 128)
+ && !(tmp_connection.protocol.http.parsing_state == parsing_post_attributes && blob_curr == ATTRIBUT_RESPONSE_61_ + 128)
+#endif
+#endif
+ )
+#endif
+ {
+ do {
+
+ unsigned char offsetInf = 0;
+ unsigned char offsetEq = 0;
+ unsigned char blob_next;
+
+#if !defined(DISABLE_POST) || defined(HTTP_AUTH)
+ if ((tmp_connection.protocol.http.parsing_state == parsing_post_attributes
+#if defined(HTTP_AUTH) && HTTP_AUTH == HTTP_AUTH_DIGEST
+ || tmp_connection.protocol.http.parsing_state == parsing_authorization_username
+#endif
+ )
+ && tmp_char < 123 && tmp_char > 96)
+ tmp_char = tmp_char - 'a' + 'A';
+#endif
+
+ blob_curr = CONST_READ_UI8(blob);
+ blob_next = CONST_READ_UI8(++blob);
+
+ if (tmp_char != blob_curr && blob_next >= 128) {
+ blob_next = CONST_READ_UI8(++blob);
+ }
+
+ if (blob_next < 32) {
+ offsetInf += ((blob_next>>2) & 1) + ((blob_next>>1) & 1) + (blob_next & 1);
+ offsetEq = offsetInf + ((blob_next & 2)?CONST_READ_UI8(blob+1):0);
+ }
+
+ if (tmp_char == blob_curr) {
+ if (blob_next < 32) {
+ if (blob_next & 2) {
+ blob += offsetEq;
+ }
+ else {
+#if !defined(DISABLE_POST) || defined(HTTP_AUTH)
+ if (tmp_connection.protocol.http.parsing_state == parsing_post_attributes)
+ blob = blob_http_header_content;
+ else
+#endif
+#if defined(HTTP_AUTH) && HTTP_AUTH == HTTP_AUTH_DIGEST
+ if (tmp_connection.protocol.http.parsing_state == parsing_authorization_username)
+ break;
+ else
+#endif
+ output_handler = &http_404_handler;
+ break;
+ }
+ }
+ break;
+ }
+ else if (tmp_char < blob_curr) {
+ if (blob_next < 32 && blob_next & 1) {
+ blob += offsetInf;
+ }
+ else {
+#if !defined(DISABLE_POST) || defined(HTTP_AUTH)
+ if(tmp_connection.protocol.http.parsing_state == parsing_post_attributes)
+ blob = blob_http_header_content;
+ else
+#endif
+#if defined(HTTP_AUTH) && HTTP_AUTH == HTTP_AUTH_DIGEST
+ if (tmp_connection.protocol.http.parsing_state == parsing_authorization_username)
+ break;
+ else
+#endif
+ output_handler = &http_404_handler;
+ break;
+ }
+ }
+ else {
+ if (blob_next < 32 && blob_next & 4) {
+ unsigned char offsetSup = offsetEq + ((blob_next & 3)?CONST_READ_UI8(blob+(offsetInf-1)):0);
+ blob += offsetSup;
+ }
+ else {
+#if !defined(DISABLE_POST) || defined(HTTP_AUTH)
+ if(tmp_connection.protocol.http.parsing_state == parsing_post_attributes) {
+ blob = blob_http_header_content;
+ }
+ else
+#endif
+#if defined(HTTP_AUTH) && HTTP_AUTH == HTTP_AUTH_DIGEST
+ if (tmp_connection.protocol.http.parsing_state == parsing_authorization_username)
+ break;
+ else
+#endif
+ output_handler = &http_404_handler;
+ break;
+ }
+ }
+ } while(1);
+ }
+ }
+
+ /* detecting parsing_end */
+ if(
#ifndef DISABLE_POST
- if(tmp_connection.protocol.http.parsing_state == parsing_post_attributes)
- blob = blob_http_header_content;
- else
-#endif
- output_handler = &http_404_handler;
- break;
- }
- }
- } while(1);
- }
- }
- /* detecting parsing_end */
- if(
+ (tmp_connection.protocol.http.parsing_state == parsing_post_args && !tmp_connection.protocol.http.post_data->content_length) ||
+#endif
+ ((output_handler == &http_404_handler
#ifndef DISABLE_POST
- (tmp_connection.protocol.http.parsing_state == parsing_post_args && !tmp_connection.protocol.http.post_data->content_length) ||
+ || output_handler == &http_505_handler
+#endif
+#ifdef HTTP_AUTH
+ || output_handler == &http_401_handler
#endif
- ((output_handler == &http_404_handler
+ ) && tmp_connection.protocol.http.parsing_state != parsing_cmd)) {
+ tmp_connection.protocol.http.parsing_state = parsing_end;
+ tmp_connection.protocol.http.ready_to_send = 1;
+ }
+
+ if(!output_handler) {
+ tmp_connection.protocol.http.blob = blob;
+ }
+ else {
+#ifdef HTTP_AUTH
+ char stale;
+
+ /* [HTTP-Auth]:
+ * If the requested handler is restricted, we set the output handler
+ * on 401 if credentials are bad or missing, in which case we need to
+ * store the requested resource's handler into the blob field of the
+ * connection structure, in order to be able to determine when sending
+ * later which uri was requested. */
+ if (IS_RESTRICTED (output_handler)
+ && output_handler != &http_401_handler
+ && output_handler != &http_404_handler
#ifndef DISABLE_POST
- || output_handler == &http_505_handler
-#endif
- ) && tmp_connection.protocol.http.parsing_state != parsing_cmd)){
- tmp_connection.protocol.http.parsing_state = parsing_end;
- tmp_connection.protocol.http.ready_to_send = 1;
- }
- if(!output_handler)
- tmp_connection.protocol.http.blob = blob;
- else {
- if(tmp_connection.protocol.http.parsing_state != parsing_cmd) {
- tmp_connection.output_handler = output_handler;
- UI32(tmp_connection.protocol.http.next_outseqno) = UI32(current_inack);
- if(CONST_UI8(output_handler->handler_type) == type_file) {
- UI32(tmp_connection.protocol.http.final_outseqno) = UI32(tmp_connection.protocol.http.next_outseqno) + CONST_UI32(GET_FILE(output_handler).length);
- } else {
- UI32(tmp_connection.protocol.http.final_outseqno) = UI32(tmp_connection.protocol.http.next_outseqno) - 1;
- }
+ && output_handler != &http_505_handler
+#endif
+#if HTTP_AUTH == HTTP_AUTH_BASIC
+ && (!auth_data.credentials
+ || (http_basic_authenticate (output_handler,
+ (unsigned const char *)(auth_data.credentials))
+ != HTTP_AUTHENTICATE_SUCCESS))
+#elif HTTP_AUTH == HTTP_AUTH_DIGEST
+ && (!auth_data.scheme_parsed
+ || auth_data.username_blob < 128
+ || auth_data.nonce[NONCE_LEN - 1] == '\0'
+ || auth_data.response[MD5_DIGEST_LEN - 1] == '\0'
+ || (stale = http_digest_authenticate (connection,
+ output_handler,
+ &auth_data)
+ ) != HTTP_AUTHENTICATE_SUCCESS)
+#endif
+ ) {
+
+ tmp_connection.protocol.http.blob = (unsigned char*)output_handler;
+ output_handler = &http_401_handler;
+
+ /* Set ready_to_send and parsing_state on correct values if not. */
+ if (!tmp_connection.protocol.http.ready_to_send)
+ tmp_connection.protocol.http.ready_to_send = 1;
+ if (tmp_connection.protocol.http.parsing_state != parsing_end)
+ tmp_connection.protocol.http.parsing_state = parsing_end;
+
+#if HTTP_AUTH == HTTP_AUTH_BASIC
+ /* Compute credentials length and free memory */
+ if (auth_data.credentials) {
+ uint8_t i = 0;
+ while (auth_data.credentials[i++] != '\0'); /* Don't forget to count the '\0' */
+ mem_free (auth_data.credentials, i * sizeof (char));
+ }
+#endif
+ }
+#endif
+
+ if (tmp_connection.protocol.http.parsing_state != parsing_cmd) {
+ tmp_connection.output_handler = output_handler;
+ UI32(tmp_connection.protocol.http.next_outseqno) = UI32(current_inack);
+
+ if (CONST_UI8(output_handler->handler_type) == type_file) {
+#ifdef HTTP_AUTH
+ /* [HTTP-Auth]:
+ * Here, we need to compute the full length of the file, including
+ * the missing header that we dynamically generate. Please refer to
+ * http_401_handler_length definitions in auth.c for more details. */
+ if (output_handler == &http_401_handler) {
+ UI32(tmp_connection.protocol.http.final_outseqno) =
+ UI32(tmp_connection.protocol.http.next_outseqno)
+ + http_401_handler_length ((struct output_handler_t*)tmp_connection.protocol.http.blob, 0);
+ }
+ else {
+ UI32(tmp_connection.protocol.http.final_outseqno) =
+ UI32(tmp_connection.protocol.http.next_outseqno)
+ + CONST_UI32(GET_FILE(output_handler).length);
+ }
+#else
+ UI32(tmp_connection.protocol.http.final_outseqno) =
+ UI32(tmp_connection.protocol.http.next_outseqno)
+ + CONST_UI32(GET_FILE(output_handler).length);
+#endif
+ }
+ else {
+ UI32(tmp_connection.protocol.http.final_outseqno) = UI32(tmp_connection.protocol.http.next_outseqno) - 1;
+ }
+
#ifndef DISABLE_COMET
- tmp_connection.protocol.http.comet_send_ack = CONST_UI8(output_handler->handler_comet) ? 1 : 0;
- tmp_connection.protocol.http.comet_passive = 0;
- tmp_connection.protocol.http.comet_streaming = 0;
+ tmp_connection.protocol.http.comet_send_ack = CONST_UI8(output_handler->handler_comet) ? 1 : 0;
+ tmp_connection.protocol.http.comet_passive = 0;
+ tmp_connection.protocol.http.comet_streaming = 0;
#endif
- }
- if(tmp_connection.protocol.http.parsing_state == parsing_end || tmp_connection.protocol.http.parsing_state == parsing_cmd){
+ }
+
+ if(tmp_connection.protocol.http.parsing_state == parsing_end || tmp_connection.protocol.http.parsing_state == parsing_cmd){
#ifndef DISABLE_POST
- /* cleaning memory */
- if(tmp_connection.protocol.http.post_data){ /* Warning : don't clean post_data, useful in output function (unless error 404 or 505) */
- if(tmp_connection.protocol.http.post_data->filename){
- uint8_t i = 0;
- while(tmp_connection.protocol.http.post_data->filename[i++] != '\0');
- mem_free(tmp_connection.protocol.http.post_data->filename,i*sizeof(char));
- tmp_connection.protocol.http.post_data->filename = NULL;
- }
- if(tmp_connection.protocol.http.post_data->boundary){
- if(tmp_connection.protocol.http.post_data->boundary->boundary_ref && tmp_connection.protocol.http.post_data->content_length != (uint16_t)-1)
- mem_free(tmp_connection.protocol.http.post_data->boundary->boundary_ref,tmp_connection.protocol.http.post_data->boundary->boundary_size*sizeof(char));
- if(tmp_connection.protocol.http.post_data->boundary->boundary_buffer)
- mem_free(tmp_connection.protocol.http.post_data->boundary->boundary_buffer,(tmp_connection.protocol.http.post_data->boundary->boundary_size)*sizeof(char));
- mem_free(tmp_connection.protocol.http.post_data->boundary,sizeof(struct boundary_t));
- }
- tmp_connection.protocol.http.post_data->boundary = NULL;
- }
- if(output_handler == &http_404_handler
+ /* cleaning memory */
+ if(tmp_connection.protocol.http.post_data){ /* Warning : don't clean post_data, useful in output function (unless error 404 or 505) */
+ if(tmp_connection.protocol.http.post_data->filename){
+ uint8_t i = 0;
+ while(tmp_connection.protocol.http.post_data->filename[i++] != '\0');
+ mem_free(tmp_connection.protocol.http.post_data->filename,i*sizeof(char));
+ tmp_connection.protocol.http.post_data->filename = NULL;
+ }
+ if(tmp_connection.protocol.http.post_data->boundary){
+ if(tmp_connection.protocol.http.post_data->boundary->boundary_ref && tmp_connection.protocol.http.post_data->content_length != (uint16_t)-1)
+ mem_free(tmp_connection.protocol.http.post_data->boundary->boundary_ref,tmp_connection.protocol.http.post_data->boundary->boundary_size*sizeof(char));
+ if(tmp_connection.protocol.http.post_data->boundary->boundary_buffer)
+ mem_free(tmp_connection.protocol.http.post_data->boundary->boundary_buffer,(tmp_connection.protocol.http.post_data->boundary->boundary_size)*sizeof(char));
+ mem_free(tmp_connection.protocol.http.post_data->boundary,sizeof(struct boundary_t));
+ }
+ tmp_connection.protocol.http.post_data->boundary = NULL;
+ }
+
+ if(output_handler == &http_404_handler
#ifndef DISABLE_POST
- || output_handler == &http_505_handler
-#endif
- ){
- /* cleaning post_data if error */
- if(tmp_connection.protocol.http.post_data){
- mem_free(tmp_connection.protocol.http.post_data,sizeof(struct post_data_t));
- tmp_connection.protocol.http.post_data = NULL;
- }
+ || output_handler == &http_505_handler
+#endif
+ ){
+ /* cleaning post_data if error */
+ if(tmp_connection.protocol.http.post_data){
+ mem_free(tmp_connection.protocol.http.post_data,sizeof(struct post_data_t));
+ tmp_connection.protocol.http.post_data = NULL;
+ }
#ifndef DISABLE_ARGS
- /* cleaning args data if error */
- if(tmp_connection.protocol.http.args){
- mem_free(tmp_connection.protocol.http.args,tmp_args_size_ref);
- tmp_connection.protocol.http.args = NULL;
- }
+ /* cleaning args data if error */
+ if(tmp_connection.protocol.http.args){
+ mem_free(tmp_connection.protocol.http.args,tmp_args_size_ref);
+ tmp_connection.protocol.http.args = NULL;
+ }
#endif
- }
+ }
+#endif
+ tmp_connection.protocol.http.parsing_state = parsing_out;
+
+#ifdef HTTP_AUTH
+ /* [HTTP-Auth]:
+ * If output_handler is the 401 handler, we cannot reset the blob field
+ * of the temporary connection structure for now, 'cause we need to
+ * keep a reference to the originally requested handler. */
+ if (output_handler != &http_401_handler)
+ tmp_connection.protocol.http.blob = blob_http_rqt;
+#else
+ tmp_connection.protocol.http.blob = blob_http_rqt;
#endif
- tmp_connection.protocol.http.parsing_state = parsing_out;
- tmp_connection.protocol.http.blob = blob_http_rqt;
+
#ifndef DISABLE_ARGS
- tmp_connection.protocol.http.arg_ref_index = 128;
+ tmp_connection.protocol.http.arg_ref_index = 128;
#endif
- }
- else
- tmp_connection.protocol.http.blob = blob;
- }
+ }
+ else
+ tmp_connection.protocol.http.blob = blob;
}
- /* drop remaining TCP data */
- while(x++ < segment_length)
- DEV_GETC(tmp_char);
+ }
- /* acknowledge received and processed TCP data if no there is no current output_handler */
- if(!tmp_connection.output_handler && tmp_connection.protocol.http.tcp_state == tcp_established && segment_length) {
- tmp_connection.output_handler = &ref_ack;
- }
+ /* drop remaining TCP data */
+ while(x++ < segment_length)
+ DEV_GETC(tmp_char);
- /* check TCP checksum using the partially precalculated pseudo header checksum */
- checksum_end();
- if(UI16(current_checksum) == TCP_CHK_CONSTANT_PART) {
- if(defer_clean_service) { /* free in-flight segment information for acknowledged segments */
+ /* acknowledge received and processed TCP data if no there is no current output_handler */
+ if(!tmp_connection.output_handler && tmp_connection.protocol.http.tcp_state == tcp_established && segment_length) {
+ tmp_connection.output_handler = &ref_ack;
+ }
+
+ /* check TCP checksum using the partially precalculated pseudo header checksum */
+ checksum_end();
+ if(UI16(current_checksum) == TCP_CHK_CONSTANT_PART) {
+ if(defer_clean_service) { /* free in-flight segment information for acknowledged segments */
#ifdef DISABLE_COROUTINES
- DYNAMIC_STATE_CHANGE(ack_received);
- /* received ack of the last dynamic segment, dynamic handling is done */
- if (curr_output.dynamic_service_state != none && /* Dynamic content is served */
- tmp_connection.protocol.http.generator_service == curr_output.service && /* This is the currently served dynamic connection */
- !curr_output.in_handler && /* Dynamic handler is finished */
- (curr_output.service_header == header_standard || /* Ack from a single segment data */
- (curr_output.service_header == header_none && curr_output.content_length == 0))) /* or the ack of the last void chunk */
- {
- DYNAMIC_STATE_CHANGE(none);
- /* When no coroutine, we only have one in_flight_infos. Thus, it has do be freed only at the end */
- clean_service(tmp_connection.protocol.http.generator_service, current_inack);
- }
+ DYNAMIC_STATE_CHANGE(ack_received);
+ /* received ack of the last dynamic segment, dynamic handling is done */
+ if (curr_output.dynamic_service_state != none && /* Dynamic content is served */
+ tmp_connection.protocol.http.generator_service == curr_output.service && /* This is the currently served dynamic connection */
+ !curr_output.in_handler && /* Dynamic handler is finished */
+ (curr_output.service_header == header_standard || /* Ack from a single segment data */
+ (curr_output.service_header == header_none && curr_output.content_length == 0))) /* or the ack of the last void chunk */
+ {
+ DYNAMIC_STATE_CHANGE(none);
+ /* When no coroutine, we only have one in_flight_infos. Thus, it has do be freed only at the end */
+ clean_service(tmp_connection.protocol.http.generator_service, current_inack);
+ }
#else
- clean_service(tmp_connection.protocol.http.generator_service, current_inack);
+ clean_service(tmp_connection.protocol.http.generator_service, current_inack);
#endif
- if(defer_free_handler) { /* free handler and generator service if the service is completely acknowledged */
+ if(defer_free_handler) { /* free handler and generator service if the service is completely acknowledged */
#ifndef DISABLE_COROUTINES
- cr_clean(&tmp_connection.protocol.http.generator_service->coroutine);
+ cr_clean(&tmp_connection.protocol.http.generator_service->coroutine);
#endif
- mem_free(tmp_connection.protocol.http.generator_service, sizeof(struct generator_service_t));
- tmp_connection.protocol.http.generator_service = NULL;
+ mem_free(tmp_connection.protocol.http.generator_service, sizeof(struct generator_service_t));
+ tmp_connection.protocol.http.generator_service = NULL;
#ifndef DISABLE_ARGS
- mem_free(defer_free_args, defer_free_args_size);
+ mem_free(defer_free_args, defer_free_args_size);
#endif
- }
- }
+ }
+ }
- if(!connection && tmp_connection.protocol.http.tcp_state == tcp_syn_rcvd) {
- connection = add_connection(&tmp_connection
+ if(!connection && tmp_connection.protocol.http.tcp_state == tcp_syn_rcvd) {
+ connection = add_connection(&tmp_connection
#ifdef IPV6
- , compressed_ip_size(comp_ipv6_addr)
-#endif
- );
- /* update the pointer in the tmp_connection because
- * it will be copied later so if the pointers do not have the right value, the list
- * will be screwed */
- if (connection)
- {
- tmp_connection.prev = connection->prev;
- tmp_connection.next = connection->next;
- }
+ , compressed_ip_size(comp_ipv6_addr)
+#endif
+ );
+ /* update the pointer in the tmp_connection because
+ * it will be copied later so if the pointers do not have the right value, the list
+ * will be screwed */
+ if (connection)
+ {
+ tmp_connection.prev = connection->prev;
+ tmp_connection.next = connection->next;
}
-
- if(!connection) {
- /* no valid connection has been found for this packet, send a reset */
- UI32(tmp_connection.protocol.http.next_outseqno) = UI32(current_inack);
+ }
+
+ if(!connection) {
+ /* no valid connection has been found for this packet, send a reset */
+ UI32(tmp_connection.protocol.http.next_outseqno) = UI32(current_inack);
#ifdef IPV6
- memcpy(rst_connection.ip_addr, full_ipv6_addr, 16);
+ memcpy(rst_connection.ip_addr, full_ipv6_addr, 16);
#else
- UI32(rst_connection.ip_addr) = UI32(tmp_connection.ip_addr);
+ UI32(rst_connection.ip_addr) = UI32(tmp_connection.ip_addr);
#endif
- UI16(rst_connection.port) = UI16(tmp_connection.protocol.http.port);
- UI32(rst_connection.current_inseqno) = UI32(tmp_connection.protocol.http.current_inseqno);
- UI32(rst_connection.next_outseqno) = UI32(tmp_connection.protocol.http.next_outseqno);
- } else {
- if(tmp_connection.protocol.http.tcp_state == tcp_listen) {
+ UI16(rst_connection.port) = UI16(tmp_connection.protocol.http.port);
+ UI32(rst_connection.current_inseqno) = UI32(tmp_connection.protocol.http.current_inseqno);
+ UI32(rst_connection.next_outseqno) = UI32(tmp_connection.protocol.http.next_outseqno);
+ }
+ else {
+ if (tmp_connection.protocol.http.tcp_state == tcp_listen) {
#ifdef DISABLE_COROUTINES
- if (curr_output.dynamic_service_state != none && tmp_connection.protocol.http.generator_service == curr_output.service)
- {
- if (curr_output.in_handler)
- {
- DYNAMIC_STATE_CHANGE(connection_terminated); /* If we are still in the handler, we have to notify it of the end of the connection */
- }
- else
- DYNAMIC_STATE_CHANGE(none); /* Otherwise, the connection was closed while handling last data segment or last chunk, thus can be fully discarded.
- Turn the state to not serving dynamic */
- }
+ if (curr_output.dynamic_service_state != none && tmp_connection.protocol.http.generator_service == curr_output.service)
+ {
+ if (curr_output.in_handler)
+ {
+ DYNAMIC_STATE_CHANGE(connection_terminated); /* If we are still in the handler, we have to notify it of the end of the connection */
+ }
+ else
+ DYNAMIC_STATE_CHANGE(none); /* Otherwise, the connection was closed while handling last data segment or last chunk, thus can be fully discarded.
+ Turn the state to not serving dynamic */
+ }
+#endif
+ free_connection(connection);
+ }
+ else {
+ /* update the current connection */
+ *connection = tmp_connection;
+#ifdef HTTP_AUTH
+ /* [HTTP-Auth]:
+ * Reset the blob field of the temporary connection structure,
+ * 'cause it wasn't done before if output handler is 401. */
+ if (tmp_connection.output_handler == &http_401_handler) {
+ tmp_connection.protocol.http.blob = blob_http_rqt;
+ }
#endif
- free_connection(connection);
- } else {
- /* update the current connection */
- *connection = tmp_connection;
+
#ifdef IPV6
- copy_compressed_ip(connection->ip_addr, comp_ipv6_addr);
+ copy_compressed_ip(connection->ip_addr, comp_ipv6_addr);
#endif
- }
- }
+ }
}
- return 1;
+ }
+
+ return 1;
}
diff --git a/core/md5.c b/core/md5.c
new file mode 100644
index 0000000..188d69f
--- /dev/null
+++ b/core/md5.c
@@ -0,0 +1,345 @@
+/*
+ * Copyright or © or Copr. 2008, Simon Duquennoy
+ *
+ * Author e-mail: simon.duquennoy@lifl.fr
+ *
+ * This software is a computer program whose purpose is to design an
+ * efficient Web server for very-constrained embedded system.
+ *
+ * This software is governed by the CeCILL license under French law and
+ * abiding by the rules of distribution of free software. You can use,
+ * modify and/ or redistribute the software under the terms of the CeCILL
+ * license as circulated by CEA, CNRS and INRIA at the following URL
+ * "http://www.cecill.info".
+ *
+ * As a counterpart to the access to the source code and rights to copy,
+ * modify and redistribute granted by the license, users are provided only
+ * with a limited warranty and the software's author, the holder of the
+ * economic rights, and the successive licensors have only limited
+ * liability.
+ *
+ * In this respect, the user's attention is drawn to the risks associated
+ * with loading, using, modifying and/or developing or reproducing the
+ * software by the user in light of its specific status of free software,
+ * that may mean that it is complicated to manipulate, and that also
+ * therefore means that it is reserved for developers and experienced
+ * professionals having in-depth computer knowledge. Users are therefore
+ * encouraged to load and test the software's suitability as regards their
+ * requirements in conditions enabling the security of their systems and/or
+ * data to be ensured and, more generally, to use and operate it in the
+ * same conditions as regards security.
+ *
+ * The fact that you are presently reading this means that you have had
+ * knowledge of the CeCILL license and that you accept its terms.
+ */
+
+/*
+ * Author: Christophe Bacara
+ * Author e-mail: christophe.bacara@etudiant.univ-lille1.fr
+ *
+ * Original software written by L. Peter Deutsch, for Aladdin Enterprises
+ * Improvements and optimizations for embedded target by Christophe Bacara
+ */
+
+#include "md5.h"
+
+#define T1 T[0]
+#define T2 T[1]
+#define T3 T[2]
+#define T4 T[3]
+#define T5 T[4]
+#define T6 T[5]
+#define T7 T[6]
+#define T8 T[7]
+#define T9 T[8]
+#define T10 T[9]
+#define T11 T[10]
+#define T12 T[11]
+#define T13 T[12]
+#define T14 T[13]
+#define T15 T[14]
+#define T16 T[15]
+#define T17 T[16]
+#define T18 T[17]
+#define T19 T[18]
+#define T20 T[19]
+#define T21 T[20]
+#define T22 T[21]
+#define T23 T[22]
+#define T24 T[23]
+#define T25 T[24]
+#define T26 T[25]
+#define T27 T[26]
+#define T28 T[27]
+#define T29 T[28]
+#define T30 T[29]
+#define T31 T[30]
+#define T32 T[31]
+#define T33 T[32]
+#define T34 T[33]
+#define T35 T[34]
+#define T36 T[35]
+#define T37 T[36]
+#define T38 T[37]
+#define T39 T[38]
+#define T40 T[39]
+#define T41 T[40]
+#define T42 T[41]
+#define T43 T[42]
+#define T44 T[43]
+#define T45 T[44]
+#define T46 T[45]
+#define T47 T[46]
+#define T48 T[47]
+#define T49 T[48]
+#define T50 T[49]
+#define T51 T[50]
+#define T52 T[51]
+#define T53 T[52]
+#define T54 T[53]
+#define T55 T[54]
+#define T56 T[55]
+#define T57 T[56]
+#define T58 T[57]
+#define T59 T[58]
+#define T60 T[59]
+#define T61 T[60]
+#define T62 T[61]
+#define T63 T[62]
+#define T64 T[63]
+
+static const uint32_t T[64] = {
+ 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
+ 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
+ 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
+ 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
+ 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
+ 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
+ 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
+ 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
+ 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
+ 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
+ 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05,
+ 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
+ 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
+ 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
+ 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
+ 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391
+};
+
+/* Define the state of the MD5 Algorithm. */
+static struct {
+ md5_word_t count[2]; /* message length in bits, lsw first */
+ md5_word_t abcd[4]; /* digest buffer */
+ md5_byte_t buf[64]; /* accumulate block */
+} md5_state;
+
+/* Store the final MD5 digest */
+md5_byte_t md5_digest[16];
+
+static void md5_process(const md5_byte_t *data /* [64] */)
+{
+ md5_word_t /* Temporary word a,b,c,d */
+ a = md5_state.abcd[0], b = md5_state.abcd[1],
+ c = md5_state.abcd[2], d = md5_state.abcd[3];
+ md5_word_t t;
+ md5_word_t X[16];
+ unsigned char i;
+
+#if ENDIANNESS == LITTLE_ENDIAN
+ memcopy(X, data, 64);
+#else
+ for (i = 0; i < 16; ++i, data += 4)
+ X[i] = data[0] + (data[1] << 8) + (data[2] << 16) + (data[3] << 24);
+#endif
+
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
+
+ /* Round 1. */
+ /* Let [abcd k s i] denote the operation */
+ /* a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
+#define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
+#define SET(a, b, c, d, k, s, Ti) \
+ t = a + F(b,c,d) + X[k] + Ti; \
+ a = ROTATE_LEFT(t, s) + b
+ /* Do the following 16 operations. */
+ SET(a, b, c, d, 0, 7, T1);
+ SET(d, a, b, c, 1, 12, T2);
+ SET(c, d, a, b, 2, 17, T3);
+ SET(b, c, d, a, 3, 22, T4);
+ SET(a, b, c, d, 4, 7, T5);
+ SET(d, a, b, c, 5, 12, T6);
+ SET(c, d, a, b, 6, 17, T7);
+ SET(b, c, d, a, 7, 22, T8);
+ SET(a, b, c, d, 8, 7, T9);
+ SET(d, a, b, c, 9, 12, T10);
+ SET(c, d, a, b, 10, 17, T11);
+ SET(b, c, d, a, 11, 22, T12);
+ SET(a, b, c, d, 12, 7, T13);
+ SET(d, a, b, c, 13, 12, T14);
+ SET(c, d, a, b, 14, 17, T15);
+ SET(b, c, d, a, 15, 22, T16);
+#undef SET
+
+ /* Round 2. */
+ /* Let [abcd k s i] denote the operation */
+ /* a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
+#define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
+#define SET(a, b, c, d, k, s, Ti) \
+ t = a + G(b,c,d) + X[k] + Ti; \
+ a = ROTATE_LEFT(t, s) + b
+ /* Do the following 16 operations. */
+ SET(a, b, c, d, 1, 5, T17);
+ SET(d, a, b, c, 6, 9, T18);
+ SET(c, d, a, b, 11, 14, T19);
+ SET(b, c, d, a, 0, 20, T20);
+ SET(a, b, c, d, 5, 5, T21);
+ SET(d, a, b, c, 10, 9, T22);
+ SET(c, d, a, b, 15, 14, T23);
+ SET(b, c, d, a, 4, 20, T24);
+ SET(a, b, c, d, 9, 5, T25);
+ SET(d, a, b, c, 14, 9, T26);
+ SET(c, d, a, b, 3, 14, T27);
+ SET(b, c, d, a, 8, 20, T28);
+ SET(a, b, c, d, 13, 5, T29);
+ SET(d, a, b, c, 2, 9, T30);
+ SET(c, d, a, b, 7, 14, T31);
+ SET(b, c, d, a, 12, 20, T32);
+#undef SET
+
+ /* Round 3. */
+ /* Let [abcd k s t] denote the operation */
+ /* a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define SET(a, b, c, d, k, s, Ti) \
+ t = a + H(b,c,d) + X[k] + Ti; \
+ a = ROTATE_LEFT(t, s) + b
+ /* Do the following 16 operations. */
+ SET(a, b, c, d, 5, 4, T33);
+ SET(d, a, b, c, 8, 11, T34);
+ SET(c, d, a, b, 11, 16, T35);
+ SET(b, c, d, a, 14, 23, T36);
+ SET(a, b, c, d, 1, 4, T37);
+ SET(d, a, b, c, 4, 11, T38);
+ SET(c, d, a, b, 7, 16, T39);
+ SET(b, c, d, a, 10, 23, T40);
+ SET(a, b, c, d, 13, 4, T41);
+ SET(d, a, b, c, 0, 11, T42);
+ SET(c, d, a, b, 3, 16, T43);
+ SET(b, c, d, a, 6, 23, T44);
+ SET(a, b, c, d, 9, 4, T45);
+ SET(d, a, b, c, 12, 11, T46);
+ SET(c, d, a, b, 15, 16, T47);
+ SET(b, c, d, a, 2, 23, T48);
+#undef SET
+
+ /* Round 4. */
+ /* Let [abcd k s t] denote the operation */
+ /* a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
+#define I(x, y, z) ((y) ^ ((x) | ~(z)))
+#define SET(a, b, c, d, k, s, Ti) \
+ t = a + I(b,c,d) + X[k] + Ti; \
+ a = ROTATE_LEFT(t, s) + b
+ /* Do the following 16 operations. */
+ SET(a, b, c, d, 0, 6, T49);
+ SET(d, a, b, c, 7, 10, T50);
+ SET(c, d, a, b, 14, 15, T51);
+ SET(b, c, d, a, 5, 21, T52);
+ SET(a, b, c, d, 12, 6, T53);
+ SET(d, a, b, c, 3, 10, T54);
+ SET(c, d, a, b, 10, 15, T55);
+ SET(b, c, d, a, 1, 21, T56);
+ SET(a, b, c, d, 8, 6, T57);
+ SET(d, a, b, c, 15, 10, T58);
+ SET(c, d, a, b, 6, 15, T59);
+ SET(b, c, d, a, 13, 21, T60);
+ SET(a, b, c, d, 4, 6, T61);
+ SET(d, a, b, c, 11, 10, T62);
+ SET(c, d, a, b, 2, 15, T63);
+ SET(b, c, d, a, 9, 21, T64);
+#undef SET
+
+ /* Then perform the following additions. (That is increment each */
+ /* of the four registers by the value it had before this block */
+ /* was started.) */
+ md5_state.abcd[0] += a;
+ md5_state.abcd[1] += b;
+ md5_state.abcd[2] += c;
+ md5_state.abcd[3] += d;
+}
+
+void md5_init()
+{
+ md5_state.count[0] = 0;
+ md5_state.count[1] = 0;
+ md5_state.abcd[0] = 0x67452301;
+ md5_state.abcd[1] = 0xefcdab89;
+ md5_state.abcd[2] = 0x98badcfe;
+ md5_state.abcd[3] = 0x10325476;
+}
+
+void md5_append(const md5_byte_t *data, uint32_t nbytes)
+{
+ uint32_t offset = (md5_state.count[0] >> 3) & 63;
+ md5_word_t nbits = (md5_word_t)(nbytes << 3);
+
+ if (nbytes <= 0)
+ return;
+
+ /* Update the message length. */
+ md5_state.count[1] += nbytes >> 29;
+ md5_state.count[0] += nbits;
+ if (md5_state.count[0] < nbits)
+ md5_state.count[1]++;
+
+ /* Process an initial partial block. */
+ if (offset) {
+ uint32_t copy = (offset + nbytes > 64 ? 64 - offset : nbytes);
+
+ memcopy(md5_state.buf + offset, data, copy);
+ if (offset + copy < 64)
+ return;
+ data += copy;
+ nbytes -= copy;
+ md5_process(md5_state.buf);
+ }
+
+ /* Process full blocks. */
+ for (; nbytes >= 64; data += 64, nbytes -= 64)
+ md5_process(data);
+
+ /* Process a final partial block. */
+ if (nbytes)
+ memcopy(md5_state.buf, data, nbytes);
+}
+
+void md5_end()
+{
+ static const md5_byte_t pad[64] = {
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+ md5_byte_t data[8];
+ int i;
+
+ /* Save the length before padding. */
+ for (i = 0; i < 8; ++i)
+ data[i] = (md5_byte_t)(md5_state.count[i >> 2] >> ((i & 3) << 3));
+ /* Pad to 56 bytes mod 64. */
+ md5_append(pad, ((55 - (md5_state.count[0] >> 3)) & 63) + 1);
+ /* Append the length. */
+ md5_append(data, 8);
+
+ for (i = 0; i < 16; ++i)
+ md5_digest[i] = (md5_byte_t)(md5_state.abcd[i >> 2] >> ((i & 3) << 3));
+}
+
+/* Useful for improved version of processing */
+/* static const uint8_t R[64] = { */
+/* 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, */
+/* 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, */
+/* 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, */
+/* 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21 */
+/* }; */
diff --git a/core/md5.h b/core/md5.h
new file mode 100644
index 0000000..d7662ee
--- /dev/null
+++ b/core/md5.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright or © or Copr. 2008, Simon Duquennoy
+ *
+ * Author e-mail: simon.duquennoy@lifl.fr
+ *
+ * This software is a computer program whose purpose is to design an
+ * efficient Web server for very-constrained embedded system.
+ *
+ * This software is governed by the CeCILL license under French law and
+ * abiding by the rules of distribution of free software. You can use,
+ * modify and/ or redistribute the software under the terms of the CeCILL
+ * license as circulated by CEA, CNRS and INRIA at the following URL
+ * "http://www.cecill.info".
+ *
+ * As a counterpart to the access to the source code and rights to copy,
+ * modify and redistribute granted by the license, users are provided only
+ * with a limited warranty and the software's author, the holder of the
+ * economic rights, and the successive licensors have only limited
+ * liability.
+ *
+ * In this respect, the user's attention is drawn to the risks associated
+ * with loading, using, modifying and/or developing or reproducing the
+ * software by the user in light of its specific status of free software,
+ * that may mean that it is complicated to manipulate, and that also
+ * therefore means that it is reserved for developers and experienced
+ * professionals having in-depth computer knowledge. Users are therefore
+ * encouraged to load and test the software's suitability as regards their
+ * requirements in conditions enabling the security of their systems and/or
+ * data to be ensured and, more generally, to use and operate it in the
+ * same conditions as regards security.
+ *
+ * The fact that you are presently reading this means that you have had
+ * knowledge of the CeCILL license and that you accept its terms.
+ */
+
+/*
+ * Author: Christophe Bacara
+ * `-Mail: christophe.bacara@etudiant.univ-lille1.fr
+ *
+ * Original software written by L. Peter Deutsch, for Aladdin Enterprises
+ * Few improvements for embedded target by Christophe Bacara
+ */
+
+#ifndef __MD5_H__
+#define __MD5_H__
+
+#include "utils.h"
+
+#include
+#include
+
+#define MD5_DIGEST_LEN 32
+
+/* As digest is stored on 16 bytes, useful to get the nth character
+ * of the hexadecimal representation of the digest */
+#define MD5_DIGEST_GET_NTH_HEXC(i) \
+ (hex_char[((i & 1) ? (md5_digest[i >> 1] & 0x0f) : ((md5_digest[i >> 1] & 0xf0) >> 4))])
+
+/* Internal type definitions */
+typedef unsigned char md5_byte_t; /* 8-bit byte */
+typedef uint32_t md5_word_t; /* 32-bit word */
+
+/* Digest storage */
+extern md5_byte_t md5_digest[16];
+
+/* Initialize the algorithm. */
+extern void md5_init();
+/* Append a string to the message. */
+extern void md5_append(const md5_byte_t *data, uint32_t nbytes);
+/* Finish the message and return the digest. */
+extern void md5_end();
+
+#endif
diff --git a/core/output.c b/core/output.c
index 74b064c..ea9745d 100644
--- a/core/output.c
+++ b/core/output.c
@@ -43,11 +43,14 @@
#include "memory.h"
#include "input.h" /* for *_HEADER_SIZE defines */
#include "handlers.h"
-
-#ifndef DISABLE_POST
#include "defines.h"
+
+#ifdef HTTP_AUTH
+#include "auth.h" /* For authentication header and nonce control */
#endif
+#include
+
/* IPV6 Common values */
#ifdef IPV6
@@ -101,7 +104,6 @@ static CONST_VAR (char, serviceHttpHeaderChunked[]) = "HTTP/1.1 200 OK\r\nConten
#define MIN(a,b) ((a) < (b) ? (a) : (b))
-
struct curr_output_t curr_output;
/* default DEV_PUT16 */
@@ -264,6 +266,13 @@ void smews_send_packet (struct connection *connection)
unsigned char full_ipv6_addr[16];
#endif
+#ifdef HTTP_AUTH
+ /* Buffer for dynamic header length */
+ uint16_t dynamic_header_length;
+ /* Buffer for static file length */
+ uint16_t static_length;
+#endif
+
#ifdef SMEWS_SENDING
SMEWS_SENDING;
#endif
@@ -312,7 +321,25 @@ void smews_send_packet (struct connection *connection)
max_out_size = MAX_OUT_SIZE (connection->protocol.http.tcp_mss);
file_remaining_bytes = UI32 (connection->protocol.http.final_outseqno) - UI32 (next_outseqno);
segment_length = file_remaining_bytes > max_out_size ? max_out_size : file_remaining_bytes;
+
+#ifdef HTTP_AUTH
+ if (output_handler == &http_401_handler) {
+ /* Compute generated header length */
+ dynamic_header_length = http_401_handler_dynamic_header_length
+ ((struct output_handler_t*)connection->protocol.http.blob, 0);
+ /* Compute index in file while aware of the generated length */
+ index_in_file =
+ CONST_UI32 (GET_FILE (output_handler).length)
+ + dynamic_header_length
+ - file_remaining_bytes;
+ /* Save static length */
+ static_length = segment_length - dynamic_header_length;
+ }
+ else
+ index_in_file = CONST_UI32 (GET_FILE (output_handler).length) - file_remaining_bytes;
+#else
index_in_file = CONST_UI32 (GET_FILE (output_handler).length) - file_remaining_bytes;
+#endif
break;
}
case type_generator:
@@ -394,7 +421,7 @@ void smews_send_packet (struct connection *connection)
}
else
#endif
- UI16 (current_checksum) = BASIC_IP_CHK;
+ UI16 (current_checksum) = BASIC_IP_CHK;
checksum_add32 (local_ip_addr);
checksum_add16 (segment_length + IP_HEADER_SIZE + TCP_HEADER_SIZE);
@@ -538,16 +565,68 @@ void smews_send_packet (struct connection *connection)
{
uint16_t i;
uint32_t tmp_sum = 0;
+
uint16_t *tmpptr =
- (uint16_t *) CONST_ADDR (GET_FILE (output_handler).chk) +
- DIV_BY_CHUNCKS_SIZE (index_in_file);
+ (uint16_t *) CONST_ADDR (GET_FILE (output_handler).chk)
+ + DIV_BY_CHUNCKS_SIZE (index_in_file);
+
+#ifdef HTTP_AUTH
+ /* [HTTP-Auth]:
+ * Checksum the dynamically generated header. Be careful
+ * about odd alignment solved by space insertion. */
+ if (output_handler == &http_401_handler) {
+ /* Getting the realm */
+ unsigned const char *char_p =
+ ((struct output_handler_t*)(connection->protocol.http.blob))->handler_restriction.realm;
+
+ /* Precalculated checksum */
+ checksum_add16 (HTTP_AUTHENTICATE_HEADER_CHK);
+
+ /* Checksum the double quoted realm */
+ checksum_add ('"');
+ while (*char_p){
+ checksum_add (*char_p++);
+ ++tmp_sum;
+ }
+ checksum_add ('"');
+
+ /* Add a space after the double quote if realm is odd string */
+ if (tmp_sum % 2)
+ checksum_add (0x20);
+
+#if HTTP_AUTH == HTTP_AUTH_DIGEST
+ /* Precalculated checksum */
+ checksum_add16 (HTTP_AUTHENTICATE_HEADER_NONCE_CHK);
+
+ /* Checksum the double quoted nonce */
+ checksum_add ('"');
+ for (i = 0; i < NONCE_LEN; ++i)
+ checksum_add (nonce_state.nonce[i]);
+ checksum_add ('"');
+#endif
+ }
+ else
+ /* If output_handler is not the 401 handler, static length
+ * is segment length. */
+ static_length = segment_length;
+ tmp_sum = 0;
+ for (i = 0; i < GET_NB_BLOCKS (static_length); i++)
+ {
+ tmp_sum += CONST_READ_UI16 (tmpptr++);
+ }
+
+ checksum_add32 ((const unsigned char *) &tmp_sum);
+ break;
+#else
for (i = 0; i < GET_NB_BLOCKS (segment_length); i++)
{
tmp_sum += CONST_READ_UI16 (tmpptr++);
}
+
checksum_add32 ((const unsigned char *) &tmp_sum);
break;
+#endif
}
default: /* Should never happen but avoids compile warnings */
return;
@@ -597,12 +676,56 @@ void smews_send_packet (struct connection *connection)
break;
case type_file:
{
- /* Send the payload of the packet */
- const char *tmpptr =
- (const char *) (CONST_ADDR (GET_FILE (output_handler).data) +
- index_in_file);
+ /* Send the payload of the packet */
+ unsigned const char *tmpptr;
+#ifdef HTTP_AUTH
+ unsigned const char *param;
+ uint8_t tmp;
+
+ if (output_handler == &http_401_handler) {
+ /* Sending the http header */
+ DEV_PUTN_CONST (HttpAuthenticateHeader, HTTP_AUTHENTICATE_HEADER_LEN);
+
+ /* Sending the double quoted realm */
+ param =
+ ((struct output_handler_t*)(connection->protocol.http.blob))->handler_restriction.realm;
+ tmpptr = param;
+ tmp = 0;
+ while (*tmpptr++)
+ ++tmp;
+
+ DEV_PUT ('"');
+ DEV_PUTN_CONST (param, tmp);
+ DEV_PUT ('"');
+
+ if (tmp % 2)
+ DEV_PUT (' ');
+
+#if HTTP_AUTH == HTTP_AUTH_DIGEST
+ /* Sending the second part of the http header */
+ DEV_PUTN_CONST (HttpAuthenticateHeaderNonce, HTTP_AUTHENTICATE_HEADER_NONCE_LEN);
+
+ /* Sending the double quoted nonce */
+ DEV_PUT ('"');
+ DEV_PUTN (nonce_state.nonce, NONCE_LEN);
+ DEV_PUT ('"');
+#endif
+ }
+#endif
+
+ tmpptr = (unsigned const char*)(CONST_ADDR (GET_FILE (output_handler).data) + index_in_file);
+
+#ifdef HTTP_AUTH
+ if (output_handler == &http_401_handler) {
+ DEV_PUTN_CONST (tmpptr, static_length);
+ }
+ else {
DEV_PUTN_CONST (tmpptr, segment_length);
- break;
+ }
+#else
+ DEV_PUTN_CONST (tmpptr, segment_length);
+#endif
+ break;
}
default: /* Should never happen but avoid warnings */
return;
@@ -680,7 +803,6 @@ char smews_send (void)
struct connection *active_connection = NULL;
const struct output_handler_t * /*CONST_VAR */ old_output_handler = NULL;
-
/* sending reset has the highest priority */
if (UI16 (rst_connection.port))
{
@@ -880,6 +1002,7 @@ char smews_send (void)
* This step has to be done before before any context_restore or context_backup */
if (cr_prepare (&curr_output.service->coroutine) == NULL)
return 1;
+
#else
/* If no coroutines, then having smews_send called while in a handler is equivalent to
retransmit the buffer (as the type is forced to persistent)
diff --git a/core/smews.h b/core/smews.h
index d58cef9..edcce16 100644
--- a/core/smews.h
+++ b/core/smews.h
@@ -43,6 +43,10 @@
#include "timers.h"
#include "memory.h"
+#if defined(HTTP_AUTH) && HTTP_AUTH == HTTP_AUTH_DIGEST
+#include "auth.h"
+#endif
+
extern void smews_retransmit(void);
/* Inlinged because used only once */
@@ -102,6 +106,9 @@ static inline void smews_init(void) {
#ifndef DISABLE_TIMERS
set_timer(&smews_retransmit,1000);
#endif
+#if defined(HTTP_AUTH) && HTTP_AUTH == HTTP_AUTH_DIGEST
+ http_auth_gen_nonce();
+#endif
}
#endif /* __SMEWS_H__ */
diff --git a/core/utils.c b/core/utils.c
new file mode 100644
index 0000000..e488bf2
--- /dev/null
+++ b/core/utils.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright or © or Copr. 2008, Simon Duquennoy
+ *
+ * Author e-mail: simon.duquennoy@lifl.fr
+ *
+ * This software is a computer program whose purpose is to design an
+ * efficient Web server for very-constrained embedded system.
+ *
+ * This software is governed by the CeCILL license under French law and
+ * abiding by the rules of distribution of free software. You can use,
+ * modify and/ or redistribute the software under the terms of the CeCILL
+ * license as circulated by CEA, CNRS and INRIA at the following URL
+ * "http://www.cecill.info".
+ *
+ * As a counterpart to the access to the source code and rights to copy,
+ * modify and redistribute granted by the license, users are provided only
+ * with a limited warranty and the software's author, the holder of the
+ * economic rights, and the successive licensors have only limited
+ * liability.
+ *
+ * In this respect, the user's attention is drawn to the risks associated
+ * with loading, using, modifying and/or developing or reproducing the
+ * software by the user in light of its specific status of free software,
+ * that may mean that it is complicated to manipulate, and that also
+ * therefore means that it is reserved for developers and experienced
+ * professionals having in-depth computer knowledge. Users are therefore
+ * encouraged to load and test the software's suitability as regards their
+ * requirements in conditions enabling the security of their systems and/or
+ * data to be ensured and, more generally, to use and operate it in the
+ * same conditions as regards security.
+ *
+ * The fact that you are presently reading this means that you have had
+ * knowledge of the CeCILL license and that you accept its terms.
+ */
+
+/*
+ * Author: Christophe Bacara
+ * `-Mail: christophe.bacara@etudiant.univ-lille1.fr
+ */
+
+#include "utils.h"
+
+unsigned const char hex_char[16] = {
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
+};
+
+void memcopy(void *dst, const void *src, uint32_t nbytes)
+{
+ while (nbytes--)
+ *(uint8_t *)(dst++) = *(uint8_t *)(src++);
+}
diff --git a/core/utils.h b/core/utils.h
new file mode 100644
index 0000000..da5a05f
--- /dev/null
+++ b/core/utils.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright or © or Copr. 2008, Simon Duquennoy
+ *
+ * Author e-mail: simon.duquennoy@lifl.fr
+ *
+ * This software is a computer program whose purpose is to design an
+ * efficient Web server for very-constrained embedded system.
+ *
+ * This software is governed by the CeCILL license under French law and
+ * abiding by the rules of distribution of free software. You can use,
+ * modify and/ or redistribute the software under the terms of the CeCILL
+ * license as circulated by CEA, CNRS and INRIA at the following URL
+ * "http://www.cecill.info".
+ *
+ * As a counterpart to the access to the source code and rights to copy,
+ * modify and redistribute granted by the license, users are provided only
+ * with a limited warranty and the software's author, the holder of the
+ * economic rights, and the successive licensors have only limited
+ * liability.
+ *
+ * In this respect, the user's attention is drawn to the risks associated
+ * with loading, using, modifying and/or developing or reproducing the
+ * software by the user in light of its specific status of free software,
+ * that may mean that it is complicated to manipulate, and that also
+ * therefore means that it is reserved for developers and experienced
+ * professionals having in-depth computer knowledge. Users are therefore
+ * encouraged to load and test the software's suitability as regards their
+ * requirements in conditions enabling the security of their systems and/or
+ * data to be ensured and, more generally, to use and operate it in the
+ * same conditions as regards security.
+ *
+ * The fact that you are presently reading this means that you have had
+ * knowledge of the CeCILL license and that you accept its terms.
+ */
+
+/*
+ * Author: Christophe Bacara
+ * `-Mail: christophe.bacara@etudiant.univ-lille1.fr
+ */
+
+#ifndef __UTILS_H__
+#define __UTILS_H__
+
+#include "types.h"
+
+#define LOWER_CASE(c) \
+ (c >= 65 && c <= 90 ? c - 'A' + 'a' : c)
+#define UPPER_CASE(c) \
+ (c >= 97 && c <= 122 ? c - 'a' + 'A' : c)
+
+#define IS_B64_CHAR(c) \
+ ((c >= 97 && c <= 122) \
+ || (c >= 65 && c <= 90) \
+ || (c >= 48 && c <= 57) \
+ || (c == '/') \
+ || (c == '+') \
+ || (c == '='))
+#define IS_HEX_CHAR(c) \
+ ((c >= 97 && c <= 102) \
+ || (c >= 65 && c <= 70) \
+ || (c >= 48 && c <= 57))
+#define IS_LWS_CHAR(c) \
+ (c == ' ' || c == '\t')
+
+#define GET_HEXC(i) \
+ ((i >= 0 && i <= 16) ? hex_char[i] : 0)
+
+/* Store each hexadecimal character with its value as index */
+extern unsigned const char hex_char[16];
+
+/* Copy nbytes bytes from src to dst. */
+extern void memcopy(void *dst, const void *src, uint32_t nbytes);
+
+
+
+#endif
diff --git a/doc/userguide.pdf b/doc/userguide.pdf
index 8e8ff28..29982cb 100644
Binary files a/doc/userguide.pdf and b/doc/userguide.pdf differ
diff --git a/tools/GenApps.py b/tools/GenApps.py
index 83ca98b..730992a 100755
--- a/tools/GenApps.py
+++ b/tools/GenApps.py
@@ -34,6 +34,7 @@
import xml.parsers.expat
import GenBlob
+import GenAuthData
import os
import gzip
import StringIO
@@ -42,6 +43,7 @@
import time
import datetime
import re
+import hashlib
# initialization
propertiesInfos = None
@@ -53,6 +55,7 @@
requestList = []
attributListFileName = os.path.join('tools','supportedPostAttributList')
attributList = []
+httpAuthUsedUsernames = GenAuthData.getUsedUsernamesList()
contentTypeList = []
postList = []
# doGet:1 doPost:2 doPostIn:4 doPostOut:8 args:16 content-types:32 doPacketIn:64 doPacketOut: 128
@@ -105,6 +108,12 @@ def generateBlobsH(dstFile):
GenBlob.genBlobTree(hOut,requestList,'blob_http_rqt',False)
GenBlob.genBlobTree(hOut,mimesListPost,'mimes_tree',False)
GenBlob.genBlobTree(hOut,attributList,'blob_http_header_content',False)
+
+ userList = [ ]
+ for user in httpAuthUsedUsernames:
+ userList.append(user.upper())
+ GenBlob.genBlobTree(hOut,userList,'usernames_tree',False)
+
hOut.write('\n#endif\n')
hOut.close()
@@ -367,14 +376,20 @@ def generateResourceProps(srcFile,dstFileInfos):
pOut.close()
# launches a Web applicative resource file generation
-def generateResource(srcFile,dstFile,chuncksNbits,gzipped,dstFileInfos):
+def generateResource(srcFile,dstFile,chuncksNbits,gzipped,dstFileInfos,authType,realm,offsetCountCouple,finalUri):
if getResourceType(srcFile) == DynamicResource:
- generateDynamicResource(srcFile,dstFile,dstFileInfos)
+ generateDynamicResource(srcFile,dstFile,dstFileInfos,authType,realm,offsetCountCouple,finalUri)
else:
- generateStaticResource(srcFile,dstFile,chuncksNbits,gzipped)
+ generateStaticResource(srcFile,dstFile,chuncksNbits,gzipped,authType,realm,offsetCountCouple,finalUri)
# dynamic resources: the generator file is enriched
-def generateDynamicResource(srcFile,dstFile,dstFileInfos):
+def generateDynamicResource(srcFile,
+ dstFile,
+ dstFileInfos,
+ authType,
+ realm,
+ offsetCountCouple,
+ finalUri):
# extract the properties from the XML (if needed)
fileData = extractPropsFromXml(srcFile,dstFileInfos)
# if the c/h file does not conatin any XML, we simply copy it: this is not a generator
@@ -390,6 +405,9 @@ def generateDynamicResource(srcFile,dstFile,dstFileInfos):
generatedHeader += '#include "stddef.h"\n\n'
generatedHeader += '#include "defines.h"\n\n'
+ if realm != '':
+ generatedHeader += '#include "http_auth_data.h"\n\n'
+
generatedOutputHandler = '/********** Output handler **********/\n'
# handler functions declaration
if dstFileInfos.has_key('init'):
@@ -513,6 +531,57 @@ def generateDynamicResource(srcFile,dstFile,dstFileInfos):
generatedOutputHandler += '\t},\n'
generatedOutputHandler += '#endif\n'
+
+ # HTTP Authentication data generation
+ generatedOutputHandler += '#ifdef HTTP_AUTH\n'
+
+ if realm != '':
+ realmVar = realm
+ for c in realmVar:
+ if (re.search('\W', c)):
+ realmVar = realmVar.replace(c, '_' + str(ord(c)) + '_')
+ generatedOutputHandler += '\t.handler_restriction = {\n'
+ generatedOutputHandler += '\t\t.realm = (unsigned char*)&' + realmVar.lower() + ',\n'
+ generatedOutputHandler += '\t\t.credentials_offset = ' + str(offsetCountCouple[0]) + ',\n'
+ generatedOutputHandler += '\t\t.credentials_count = ' + str(offsetCountCouple[1])
+ if authType == 'digest':
+ generatedOutputHandler += ',\n'
+ # Setting method string
+ if (dstFileInfos.has_key('doPost')
+ or dstFileInfos.has_key('doPostIn')
+ or dstFileInfos.has_key('doPostOut')):
+ method = 'POST'
+ else:
+ method = 'GET'
+
+ (fileName, fileExt) = os.path.splitext(finalUri)
+ if (fileExt == '.c' or fileExt == '.h'):
+ print 'URI EXTENSION STRIP !!!'
+ finalUri = fileName
+ md5 = hashlib.md5()
+ md5.update('%s:%s' % (method, finalUri))
+ hexdigest = md5.hexdigest()
+ generatedOutputHandler += '\t\t.resource_digest = "%s"\n' % hexdigest
+ # DEBUG PURPOSE
+ print 'MD5 Digest: %s (%s:%s)' % (hexdigest, method, finalUri)
+ else:
+ generatedOutputHandler += "\n"
+
+ generatedOutputHandler += '\t}\n'
+ else:
+ generatedOutputHandler += '\t.handler_restriction = {\n'
+ generatedOutputHandler += '\t\t.realm = NULL,\n'
+ generatedOutputHandler += '\t\t.credentials_offset = 0,\n'
+ generatedOutputHandler += '\t\t.credentials_count = 0'
+ if authType == 'digest':
+ generatedOutputHandler += ',\n'
+ generatedOutputHandler += '\t\t.resource_digest = ""\n'
+ else:
+ generatedOutputHandler += '\n'
+ generatedOutputHandler += '\t}\n'
+
+ generatedOutputHandler += '#endif\n'
+
generatedOutputHandler += '};\n'
if (dstFileInfos.has_key('doPost') or dstFileInfos.has_key('doPostIn')):
@@ -595,7 +664,7 @@ def generateDynamicResource(srcFile,dstFile,dstFileInfos):
# static file: the file is completely pre-processed into a c file:
# HTTP header insertion
# chuncks checksums calculation
-def generateStaticResource(srcFile,dstFile,chuncksNbits,gzipped):
+def generateStaticResource(srcFile,dstFile,chuncksNbits,gzipped,authType,realm,offsetCountCouple,finalUri):
# HTTP header generation and concatenation with file data
try:
# open the source file
@@ -627,6 +696,11 @@ def generateStaticResource(srcFile,dstFile,chuncksNbits,gzipped):
fileData = 'HTTP/1.1 404 Not Found\r\nContent-Length: ' + fileData
elif os.path.basename(srcFile) == '505.html':
fileData = 'HTTP/1.1 505 HTTP Version Not Supported\r\nContent-Length: ' + fileData
+ # bacara:
+ # HTTP Authentication needs runtime data, such as realm and nonce. At this
+ # point, we cannot process the full generation for 401.html.
+ elif os.path.basename(srcFile) == '401.html':
+ fileData = '\r\nContent-Length: ' + fileData
else:
fileData = 'HTTP/1.1 200 OK\r\nContent-Length: ' + fileData
@@ -654,6 +728,8 @@ def generateStaticResource(srcFile,dstFile,chuncksNbits,gzipped):
# inclusions
cOut.write('#include "handlers.h"\n')
+ if realm != '':
+ cOut.write('#include "http_auth_data.h"\n')
# data structures declaration
cName = getCName(srcFile)
@@ -672,6 +748,38 @@ def generateStaticResource(srcFile,dstFile,chuncksNbits,gzipped):
+ '\t\t\t.data = data_' + cName + '\n'
+ '\t\t}\n'
+ '\t},\n')
+
+ cOut.write('#ifdef HTTP_AUTH\n')
+ if realm != '':
+ realmVar = realm
+ for c in realmVar:
+ if (re.search('\W', c)):
+ realmVar = realmVar.replace(c, '_' + str(ord(c)) + '_')
+ cOut.write('\t.handler_restriction = {\n'
+ + '\t\t.realm = (unsigned char*)&' + realmVar.lower() + ',\n'
+ + '\t\t.credentials_offset = ' + str(offsetCountCouple[0]) + ',\n'
+ + '\t\t.credentials_count = ' + str(offsetCountCouple[1]) + ',\n')
+ if authType == 'digest':
+ m = hashlib.md5()
+ m.update('%s:%s' % ('GET', finalUri))
+ hexdigest = m.hexdigest()
+ cOut.write('\t\t.resource_digest = "%s"\n' % hexdigest)
+ # DEBUG PURPOSE
+ print 'MD5 Digest: %s (GET:%s)' % (hexdigest, finalUri)
+ cOut.write('\t}\n')
+ else:
+ cOut.write('\t.handler_restriction = {\n'
+ + '\t\t.realm = NULL,\n'
+ + '\t\t.credentials_offset = 0,\n'
+ + '\t\t.credentials_count = 0')
+ if authType == 'digest':
+ cOut.write(',\n\t\t.resource_digest = ""\n')
+ else:
+ cOut.write('\n')
+ cOut.write('\t}\n')
+
+ cOut.write('#endif\n')
+
cOut.write('};\n')
# chuncks checksums data generation
diff --git a/tools/GenAuthData.py b/tools/GenAuthData.py
new file mode 100644
index 0000000..716bc8b
--- /dev/null
+++ b/tools/GenAuthData.py
@@ -0,0 +1,408 @@
+#!/usr/bin/python
+
+from xml.dom import minidom
+
+import base64
+import re
+import hashlib
+
+import GenApps
+import GenBlob
+
+# -------------------------------------------------- #
+# Class: User
+# -------------------------------------------------- #
+class User:
+ def __init__(self, username, password):
+ self.username = username
+ self.password = password
+
+ def toBasicHTTPAuthString(self):
+ return base64.b64encode('%s:%s' % (self.username, self.password))
+# -------------------------------------------------- #
+
+# Script initialisation
+authenticationType = '' # 'basic' | 'digest'
+realmUrisMap = { } # Read parseAuthData description for details
+
+# XML Tag Names
+rootNodeTag = "http-authentication"
+authNodeTag = "authorizations"
+restNodeTag = "restrictions"
+userNodeTag = "user"
+realmNodeTag = "realm"
+uriNodeTag = "uri"
+
+# Effectively used usernames list
+usedUsernames = [ ]
+
+# parseAuthData(xmlFilename):
+# Parse authentication data from the corresponding XML file.
+def parseXMLFile(xmlFilename):
+ global authenticationType
+ # Getting XML document
+ xmlDoc = minidom.parse(xmlFilename)
+
+ # Getting root, authorizations, restrictions
+ rootNodeList = xmlDoc.getElementsByTagName(rootNodeTag)
+ authNodeList = xmlDoc.getElementsByTagName(authNodeTag)
+ restNodeList = xmlDoc.getElementsByTagName(restNodeTag)
+
+ if (len(rootNodeList) != 1):
+ print '%s: Must contain only one node: %s' % (xmlFilename, rootNodeTag)
+ exit()
+ if (len(authNodeList) != 1):
+ print '%s: Must contain only one node: %s' % (xmlFilename, authNodeTag)
+ exit()
+ if (len(restNodeList) != 1):
+ print '%s: Must contain only one node: %s' % (xmlFilename, restNodeTag)
+ exit()
+
+ rootNode = rootNodeList[0]
+ authNode = authNodeList[0]
+ restNode = restNodeList[0]
+
+ # Checking authentication type
+ authenticationType = rootNode.attributes['type'].value.lower()
+
+ if authenticationType != 'basic' and authenticationType != 'digest':
+ print '%s: Unknown authentication scheme: %s' % (xmlFilename, authenticationType)
+ exit()
+
+ parseAuthData(restNode, parseUsersList(authNode))
+
+ return authenticationType
+
+# parseUsersList(authorizationNode):
+# Parse the authorization node and return a list of User objects corresponding
+# to the XML data.
+def parseUsersList(authorizationNode):
+ usernames = [] # Twins checking purpose
+ usersList = []
+
+ userNodeList = authorizationNode.getElementsByTagName(userNodeTag)
+
+ # Parsing username and passwd for each user
+ for userNode in userNodeList:
+ login = userNode.attributes['login'].value
+ passwd = userNode.attributes['passwd'].value
+
+ if login in usernames: # Twins check
+ print '%s: Username is duplicated.' % (login)
+ exit()
+ if passwd == '':
+ print '%s: Password field not set or empty.' % (login)
+ exit()
+
+ usernames.append(login)
+ usersList.append(User(login, passwd))
+
+ return usersList
+
+# Parse the data corresponding to the specified restriction node, and
+# build the data structure according to the previously parsed users list.
+#
+# The returned data structure looks like this :
+#
+# /!\ HTTP BASIC AUTHENTICATION /!\
+# ret = { 'realm' : [ { 'uri' : [credentials] } ] }
+# where credentials is the base 64 encoding of the string "username:passwd"
+# .
+# |- realm1
+# | |- uri1
+# | | |- credentials1
+# | | `- credentials2
+# | `- uri2
+# | `- credentials3
+# `- realm2
+# `- uri3
+# |- credentials4
+# `- credentials5
+#
+# /!\ HTTP DIGEST AUTHENTICATION /*\
+# ret = { ('users' | 'realms') }
+# where the value associated with users is a dictionnary with username as key
+# and password as value
+# AND
+# where the value associated with realms is the same data structure as for
+# basic authentication, except about the credentials list which becomes now
+# a username list.
+# .
+# |- users
+# | `- { username : password }
+# `- realms
+# |- uri1
+# | |- user1
+# | `- user2
+# |- uri2
+# | `- user1
+# `- uri3
+# |- user1
+# `- user3
+#
+def parseAuthData(restrictionNode, usersList):
+ global realmUrisMap
+ realmNodeList = restrictionNode.getElementsByTagName(realmNodeTag)
+ mapBuilt = { }
+
+ # Parsing each restriction list (1x list/realm)
+ for realmNode in realmNodeList:
+ uriCredentialsMap = { }
+ realmName = realmNode.attributes['name'].value
+
+ if realmName in mapBuilt: # Twins check
+ print '%s: Realm is duplicated.' % (realmName)
+ exit()
+ if len(realmName) > 32: # Length check
+ print '%s: Realm name is too long.' % (realmName)
+ exit()
+
+ uriNodeList = realmNode.getElementsByTagName(uriNodeTag)
+
+ for uriNode in uriNodeList:
+ uri = uriNode.attributes['path'].value
+
+ if uri in uriCredentialsMap: # Twins check
+ print '%s: Uri is duplicated.' % (uri)
+ exit()
+
+ # Building allowed users list
+ allowedUsers = uriNode.attributes['users'].value.split(';')
+ credentials = []
+
+ for username in allowedUsers:
+ # Existence check
+ if username not in [user.username for user in usersList]:
+ print '%s: User "%s" doesn\'t exist' % (uri, username)
+ exit()
+
+ # Getting corresponding string
+ for user in usersList:
+ if user.username == username:
+ if authenticationType == 'basic':
+ credentials.append(user.toBasicHTTPAuthString())
+ elif authenticationType == 'digest':
+ credentials.append(username)
+
+ uriCredentialsMap[uri] = credentials
+
+ mapBuilt[realmName] = uriCredentialsMap
+
+ if authenticationType == 'digest':
+ digestMap = { }
+ digestMap['users'] = { }
+ for user in usersList:
+ digestMap['users'][user.username] = user.password
+ digestMap['realms'] = mapBuilt;
+ mapBuilt = digestMap;
+
+ # DEBUG PURPOSE
+# print 'USERS:'
+# for user in mapBuilt['users']:
+# print '\t' + user + ' : ' + mapBuilt['users'][user]
+#
+# print 'REALMS:'
+# for realm in mapBuilt['realms']:
+# print '\t' + realm + ':'
+# for uri in mapBuilt['realms'][realm]:
+# print '\t\t' + uri
+# for user in mapBuilt['realms'][realm][uri]:
+# print '\t\t\t' + user
+
+ realmUrisMap = mapBuilt # Saving result for code generation purpose
+ return mapBuilt
+
+def genHTTPAuthDataFile(dstFile):
+ global realmUrisMap
+ global authenticationType
+ realmUrisCredentialsDataMap = { }
+ uriDatasMap = { }
+
+ uChar = 'unsigned char'
+
+ generatedHeader = ''
+ generatedCode = ''
+
+ defHeader = '__HTTP_AUTH_DATA_H__'
+ generatedHeader += '#ifndef ' + defHeader + '\n'
+ generatedHeader += '#define ' + defHeader + '\n'
+ generatedHeader += '\n'
+ generatedHeader += '#include "types.h"\n'
+ generatedHeader += '#include "auth.h"\n'
+ generatedHeader += '\n'
+
+ generatedCode += '#include "http_auth_data.h"\n\n'
+
+ # Basic authentication
+ if (authenticationType == 'basic'):
+ credentialsList = [] # Ordered list of credentials, app by app
+ credentialsVarMap = { } # Dictionnary where key is a credentials string,
+ # and value the credentials' C identifier string.
+ credentialsCount = 0
+
+ # Write realm string declarations
+ commentary = '/*********** Realm list ***********/\n'
+ generatedHeader += commentary
+ generatedCode += commentary
+
+ offset = 0
+ for realm in realmUrisMap:
+ realmVar = realm.lower()
+ for c in realmVar:
+ if (re.search('\W', c)):
+ realmVar = realmVar.replace(c, '_' + str(ord(c)) + '_')
+
+ generatedHeader += 'extern CONST_VAR(%s, %s[]);\n' % (uChar, realmVar)
+ generatedCode += 'CONST_VAR(%s, %s[]) = "%s";\n' % (uChar, realmVar, realm)
+
+ for uri in realmUrisMap[realm]:
+ count = 0
+ for credentials in realmUrisMap[realm][uri]:
+ credentialsList.append(credentials)
+ count += 1
+
+ uriDatasMap[uri] = (offset, count)
+ offset += count
+
+ realmUrisCredentialsDataMap[realm] = uriDatasMap
+
+ generatedHeader += '\n'
+ generatedCode += '\n'
+
+ # Write basic credentials string declarations
+ commentary = '/*********** Credentials list ***********/\n'
+ generatedHeader += commentary
+ generatedCode += commentary
+
+ for credentials in credentialsList:
+ credentialsVar = credentials.lower()
+ for c in credentialsVar:
+ if (re.search('\W', c)):
+ credentialsVar = credentialsVar.replace(c, '_' + str(ord(c)) + '_')
+
+ if credentials not in credentialsVarMap:
+ credentialsVarMap[credentials] = credentialsVar
+ generatedHeader += 'extern CONST_VAR(%s, %s[]);\n' % (uChar, credentialsVar)
+ generatedCode += 'CONST_VAR(%s, %s[]) = "%s";\n' % (uChar, credentialsVar, credentials)
+
+ generatedHeader += '\n'
+ generatedCode += '\n'
+
+ # Write association table for handler->credentials
+ commentary = '/*********** Credentials string table ***********/\n'
+ generatedHeader += commentary
+ generatedCode += commentary
+
+ generatedHeader += 'extern CONST_VAR(%s*, http_auth_basic_credentials_data[]);' % (uChar)
+ generatedCode += 'CONST_VAR(%s *, http_auth_basic_credentials_data[]) = {\n' %(uChar)
+ for credentials in credentialsList:
+ generatedCode += '\t(%s *)&%s,\n' % (uChar, credentialsVarMap[credentials])
+
+ generatedHeader += '\n'
+ generatedCode += '};\n'
+
+ # Digest authentication
+ elif (authenticationType == 'digest'):
+ credentialsByUserRealm = { } # Key is (user,realm)
+
+ # Write realm string declarations
+ commentary = '/*********** Realm List ***********/\n'
+ generatedHeader += commentary
+ generatedCode += commentary
+
+ realmVars = { } # Will store the name of the character string for realms
+ realmUsers = { } # Will store the usernames used for each realm
+ global usedUsernames
+
+ for realm in realmUrisMap['realms']:
+ # Building the string identifier
+ realmVar = realm.lower()
+ for c in realmVar:
+ if (re.search('\W', c)):
+ realmVar = realmVar.replace(c, '_' + str(ord(c)) + '_')
+ # Generating the string
+ generatedHeader += 'extern CONST_VAR(%s, %s[]);\n' % (uChar, realmVar)
+ generatedCode += 'CONST_VAR(%s, %s[]) = "%s";\n' % (uChar, realmVar, realm)
+
+ realmVars[realm] = realmVar
+
+ # Building the list of users per realm
+ realmUsers[realm] = [ ]
+ for uri in realmUrisMap['realms'][realm]:
+ for user in realmUrisMap['realms'][realm][uri]:
+ realmUsers[realm].append(user)
+ if user not in usedUsernames:
+ usedUsernames.append(user)
+
+ # Building the map where (user,realm) is a key corresponding to a credentials digest
+ for realm in realmUsers:
+ for user in realmUsers[realm]:
+ m = hashlib.md5()
+ m.update(user + ':' + realm + ':' + realmUrisMap['users'][user])
+ credentialsByUserRealm[(user,realm)] = m.hexdigest()
+
+ # Write credentials digest struct table
+ commentary = '\n/*********** Credentials digest table ***********/\n'
+ generatedHeader += commentary
+ generatedCode += commentary
+
+ generatedHeader += '#define USER_DIGEST_COUNT %s\n' % len(credentialsByUserRealm)
+
+ generatedHeader += 'extern CONST_VAR(%s, %s[]);\n' % ('credentials_digest_t', 'http_auth_digest_credentials_data')
+
+ generatedCode += 'CONST_VAR(%s, %s[]) = {\n' % ('credentials_digest_t', 'http_auth_digest_credentials_data')
+
+ for key in credentialsByUserRealm:
+ generatedCode += '\t{\n'
+ generatedCode += '\t\t.username_blob = %s,\n' % str(usedUsernames.index(key[0]))
+ generatedCode += '\t\t.realm = (unsigned const char *)&%s,\n' % realmVars[key[1]]
+ generatedCode += '\t\t.user_digest = "%s"\n' % credentialsByUserRealm[key]
+ generatedCode += '\t},\n'
+
+ generatedCode += '};\n'
+
+ # Write credentials table
+ commentary = '\n/*********** Credentials table ***********/\n'
+ generatedHeader += commentary
+ generatedCode += commentary
+
+ generatedHeader += 'extern CONST_VAR(%s, %s[]);\n' % ('uint8_t', 'http_auth_digest_credentials_table')
+
+ generatedCode += 'CONST_VAR(%s, %s[]) = {\n' % ('uint8_t', 'http_auth_digest_credentials_table')
+ offset = 0;
+
+ for realm in realmUrisMap['realms']:
+ uriDatasMap = { }
+ for uri in realmUrisMap['realms'][realm]:
+ count = 0;
+ for user in realmUrisMap['realms'][realm][uri]:
+ generatedCode += '\t%s, /* %s => %s */\n' % (usedUsernames.index(user), uri, user)
+ count += 1
+
+ uriDatasMap[uri] = (offset, count)
+ offset += count
+
+ realmUrisCredentialsDataMap[realm] = uriDatasMap
+
+ generatedCode += '};\n'
+
+ generatedHeader += '\n/*********** Username blobs ***********/\n'
+ for u in usedUsernames:
+ user = u.upper()
+ generatedHeader += '#define HTTP_AUTH_USERNAME_%s\t%s\n' % (user, usedUsernames.index(u))
+
+ generatedHeader += '\n#endif\n'
+
+ headerFile = open(dstFile + '.h', 'w')
+ GenApps.writeHeader(headerFile, 0)
+ headerFile.write(generatedHeader)
+
+ cFile = open(dstFile + '.c', 'w')
+ GenApps.writeHeader(cFile, 0)
+ cFile.write(generatedCode)
+
+ return realmUrisCredentialsDataMap
+
+def getUsedUsernamesList():
+ global userUsernames
+ return usedUsernames
diff --git a/tools/supportedHttpAuthTypeList b/tools/supportedHttpAuthTypeList
new file mode 100644
index 0000000..29e858b
--- /dev/null
+++ b/tools/supportedHttpAuthTypeList
@@ -0,0 +1,2 @@
+Basic
+Digest
\ No newline at end of file
diff --git a/tools/supportedPostAttributList b/tools/supportedPostAttributList
index cc2dcc3..26602c0 100644
--- a/tools/supportedPostAttributList
+++ b/tools/supportedPostAttributList
@@ -1,4 +1,8 @@
CONTENT-TYPE
CONTENT-LENGTH
+AUTHORIZATION:
FILENAME=
BOUNDARY=
+USERNAME=
+NONCE=
+RESPONSE=