ERROR_CODE parse_url_static(char *url, size_t url_size, struct url_static_t *url_s) { /* allocates space for the temporary error variable to be used to detect errors in calls */ ERROR_CODE error; /* allocates the space for the temporary (dynamic) url structure to be used as basis for the construction of the static one */ struct url_t _url_s; error = parse_url(url, url_size, &_url_s); if(error) { RAISE_ERROR_M( RUNTIME_EXCEPTION_ERROR_CODE, (unsigned char *) "Problem parsing the url" ); } memset(url_s, 0, sizeof(struct url_static_t)); if(_url_s.scheme.buffer != NULL) { memcpy(url_s->scheme, _url_s.scheme.buffer, _url_s.scheme.length); url_s->scheme[_url_s.scheme.length] = '\0'; } if(_url_s.username.buffer != NULL) { memcpy(url_s->username, _url_s.username.buffer, _url_s.username.length); url_s->username[_url_s.username.length] = '\0'; } if(_url_s.password.buffer != NULL) { memcpy(url_s->password, _url_s.password.buffer, _url_s.password.length); url_s->password[_url_s.password.length] = '\0'; } if(_url_s.host.buffer != NULL) { memcpy(url_s->host, _url_s.host.buffer, _url_s.host.length); url_s->password[_url_s.host.length] = '\0'; } if(_url_s.port != 0) { url_s->port = _url_s.port; } if(_url_s.path.buffer != NULL) { memcpy(url_s->path, _url_s.path.buffer, _url_s.path.length); url_s->password[_url_s.path.length] = '\0'; } if(_url_s.query.buffer != NULL) { memcpy(url_s->query, _url_s.query.buffer, _url_s.query.length); url_s->password[_url_s.query.length] = '\0'; } if(_url_s.fragment.buffer != NULL) { memcpy(url_s->fragment, _url_s.fragment.buffer, _url_s.fragment.length); url_s->password[_url_s.fragment.length] = '\0'; } RAISE_NO_ERROR; }
ERROR_CODE log_http_request(char *host, char *identity, char *user, char *method, char *uri, enum http_version_e version, int error_code, size_t content_length) { /* allocates space for the buffer to hild the date and time information to be logged */ char date_buffer[1024]; /* allocates space for the internal date structures to be used for the retrieval of the time information and retrieves the current time to be used converting it then to the local time*/ struct tm *_local_time; time_t _time = time(NULL); LOCAL_TIME(_local_time, &_time); /* checks if the converted local time is invalid and in case it is raises the apropriate runtime error to be caught */ if(_local_time == NULL) { RAISE_ERROR_M( RUNTIME_EXCEPTION_ERROR_CODE, (unsigned char *) "Problem retrieving local time" ); } /* formats the local time into the data buffer and then uses it and the other (sent) variables to format the output buffer */ strftime(date_buffer, 1024, "%d/%b/%Y %H:%M:%S", _local_time); PRINTF_F( "%s %s %s [%s] \"%s %s %s\" %d %lu\n", host, identity, user, date_buffer, method, uri, http_version_codes[version - 1], error_code, (long unsigned int) content_length ); /* raises no error */ RAISE_NO_ERROR; }
ERROR_CODE parse_url(char *url, size_t url_size, struct url_t *url_s) { /* allocates space for the index and length counters to be used on the parse of the provided url */ size_t index; size_t length; /* sets space for the variables to be set with the current (byte) in parsing and for the current state of the parse */ unsigned char current; enum url_parse_state_e state; /* allocates space for the internal markers and pointers to be used durring the parsin main loop */ unsigned char *mark; unsigned char *pointer; /* creates space for a "local" buffer that is going to be used as temporary for some of the conversion operations */ unsigned char buffer[128]; /* resets the url structure by setting all of its contents to the default zero (reset) value */ memset(url_s, 0, sizeof(struct url_t)); /* sets the url pointer as the initial mark value and also sets the initial state of the parsing as the scheme state */ mark = (unsigned char *) url; state = SCHEME_STATE; /* iterate over the complete url buffer to try to gather the range of the various parts of the url */ for(index = 0; index < url_size; index++) { /* retrieves the current byte in iteration and the pointer address to the current buffer position */ current = (unsigned char) url[index]; pointer = (unsigned char *) &url[index]; switch(state) { case SCHEME_STATE: switch(current) { case ':': length = pointer - mark; url_s->scheme.buffer = mark; url_s->scheme.length = length; state = SLA_STATE; break; } break; case SLA_STATE: switch(current) { case '/': state = SLA_SLA_STATE; break; default: goto error; break; } break; case SLA_SLA_STATE: switch(current) { case '/': state = AUTH_STATE; mark = pointer + 1; break; default: goto error; break; } break; case AUTH_STATE: switch(current) { case '/': length = pointer - mark; url_s->host_c.buffer = mark; url_s->host_c.length = length; state = PATH_STATE; mark = pointer; break; case '@': length = pointer - mark; url_s->auth.buffer = mark; url_s->auth.length = length; state = HOST_STATE; mark = pointer + 1; break; } break; case HOST_STATE: switch(current) { case '/': length = pointer - mark; url_s->host.buffer = mark; url_s->host.length = length; state = PATH_STATE; mark = pointer; break; case ':': length = pointer - mark; url_s->host.buffer = mark; url_s->host.length = length; state = PORT_STATE; mark = pointer + 1; break; } break; case PORT_STATE: switch(current) { case '/': length = pointer - mark; url_s->port_s.buffer = mark; url_s->port_s.length = length; state = PATH_STATE; mark = pointer; break; } break; case PATH_STATE: switch(current) { case '?': length = pointer - mark; url_s->path.buffer = mark; url_s->path.length = length; state = QUERY_STATE; mark = pointer + 1; break; } break; case QUERY_STATE: switch(current) { case '#': length = pointer - mark; url_s->query.buffer = mark; url_s->query.length = length; state = FRAGMENT_STATE; mark = pointer + 1; break; } break; case FRAGMENT_STATE: break; } } pointer++; /* runs the final swith operation to clone the still opened parse step (the final step) */ switch(state) { case PATH_STATE: length = pointer - mark; url_s->path.buffer = mark; url_s->path.length = length; break; case QUERY_STATE: length = pointer - mark; url_s->query.buffer = mark; url_s->query.length = length; break; case FRAGMENT_STATE: length = pointer - mark; url_s->fragment.buffer = mark; url_s->fragment.length = length; break; default: goto error; break; } if(url_s->host_c.buffer != NULL) { pointer = memchr(url_s->host_c.buffer, ':', url_s->host_c.length); if(pointer == NULL) { url_s->host.buffer = url_s->host_c.buffer; url_s->host.length = url_s->host_c.length; } else { url_s->host.buffer = url_s->host_c.buffer; url_s->host.length = pointer - url_s->host_c.buffer; url_s->port_s.buffer = pointer + 1; url_s->port_s.length = url_s->host_c.buffer +\ url_s->host_c.length - (pointer + 1); } } if(url_s->auth.buffer != NULL) { pointer = memchr(url_s->auth.buffer, ':', url_s->auth.length); if(pointer == NULL) { goto error; } url_s->username.buffer = url_s->auth.buffer; url_s->username.length = pointer - url_s->auth.buffer; url_s->password.buffer = pointer + 1; url_s->password.length = url_s->auth.buffer +\ url_s->auth.length - (pointer + 1); } if(url_s->port_s.buffer != NULL) { memcpy(buffer, url_s->port_s.buffer, url_s->port_s.length); buffer[url_s->port_s.length] = '\0'; url_s->port = atoi((char *) buffer); } RAISE_NO_ERROR; error: RAISE_ERROR_M( RUNTIME_EXCEPTION_ERROR_CODE, (unsigned char *) "Problem parsing url string" ); }
ERROR_CODE parameters_http_c(char *buffer, size_t size, size_t count, ...) { /* allocates space for the variable list of arguments provided as arguments to this function and tha should contain sequences of key, value and length */ va_list arguments; /* allocates space for the various indexes to be used in the iteration including the sequence offset and the global index counter */ size_t index; size_t index_g; size_t offset; /* allocates space for the three components of the parameter the key, the value and the length of the provided value buffer (it's not null terminated) */ char *key_s; char *buffer_s; size_t length_s; /* allocates space for the pointer to the buffer that will hold the created parameters string */ char *params_buffer; size_t params_size; /* creates space for the pointer to the map that will contain all the arranjed sequence of keys and values representing the various parameters */ struct hash_map_t *parameters_map; /* statically allocates space in the stack for the various value strings representing the parameter values */ struct string_t strings[256]; /* in case the number of tuples provided as arguments is more that the space available for the value strings must fail with an error otherwise a buffer overflow occurs */ if(count > 256) { RAISE_ERROR_M( RUNTIME_EXCEPTION_ERROR_CODE, (unsigned char *) "Problem creating parameters" ); } /* sets the inial key string value as null so that the value is started initialized, required for safe execution */ key_s = NULL; /* multiplies the count by three as it must contain the real number of arguments and not just the number of tuples of three in it */ count *= 3; /* creates the hash map that is going to be used to temporarly store the various key value associations */ create_hash_map(¶meters_map, 0); /* iterates over the sequence of dynamic arguments provided to the function to retrieve them as sequences of key, value and length, then sets them in the map representing the various parameters */ va_start(arguments, count); for(index = 0; index < count; index++) { offset = index % 3; index_g = index / 3; switch(offset) { case 0: key_s = va_arg(arguments, char *); break; case 1: buffer_s = va_arg(arguments, char *); strings[index_g].buffer = (unsigned char *) buffer_s; break; case 2: length_s = va_arg(arguments, size_t); strings[index_g].length = length_s; set_value_string_hash_map( parameters_map, (unsigned char *) key_s, (void *) &strings[index_g] ); break; } } va_end(arguments); /* generates the (get) parameters for an http request from the provided hash map of key values, the returned buffer is owned by the caller and must be released */ parameters_http( parameters_map, (unsigned char **) ¶ms_buffer, ¶ms_size ); delete_hash_map(parameters_map); /* in case the amount of bytes to be copied from the dynamically created params buffer to the buffer is greater than the size provided raises an error */ if(params_size > size - 1) { FREE(params_buffer); RAISE_ERROR_M( RUNTIME_EXCEPTION_ERROR_CODE, (unsigned char *) "Problem creating parameters" ); } /* copies the generated params buffer into the final buffer defined in the parameters structure, then closes the string with the final character and releases the temporary buffer (params buffer) */ memcpy(buffer, params_buffer, params_size); buffer[params_size] = '\0'; FREE(params_buffer); /* raises no error as the creation of the parameters buffer has completed with success */ RAISE_NO_ERROR; }
ERROR_CODE auth_file_http(char *auth_file, char *authorization, unsigned char *result) { /* allocates space for the error return value to be used in error checking for function calls */ ERROR_CODE return_value; /* allocates space for the pointer to the passwd key value structure to be created by parsing the auth file */ struct hash_map_t *passwd; /* allocates space to the various pointer values to be used for the separation and treatment of the auth value */ char *pointer; char *authorization_b64; char *authorization_d; char *password_pointer; /* allocates space for the buffers to be used for the username and password values extracted from the authorization token */ char username[128]; char password[128]; char *password_v; /* allocates the various size relates values for the buffer variables creation */ size_t authorization_size; size_t username_size; size_t password_size; /* tries to find the token that separates the authentication type from the authorization base 64 value in case the value is not found raises an error indicating the problem */ pointer = strchr(authorization, ' '); if(pointer == NULL) { RAISE_ERROR_M( RUNTIME_EXCEPTION_ERROR_CODE, (unsigned char *) "Authorization value not valid" ); } authorization_b64 = pointer + 1; /* tries to decode the authorization base 64 value into a plain text value in case the decoding fails, re-raises the error to the upper levels for caller information */ return_value = decode_base64( (unsigned char *) authorization_b64, strlen(authorization_b64), (unsigned char **) &authorization_d, &authorization_size ); if(IS_ERROR_CODE(return_value)) { RAISE_ERROR_M( RUNTIME_EXCEPTION_ERROR_CODE, (unsigned char *) "Problem decoding base 64 authorization" ); } /* tries to find the token that separates the username part of the authorization from the password part in case the value is not found raises an error to the upper levels */ pointer = memchr(authorization_d, ':', authorization_size); if(pointer == NULL) { FREE(authorization_d); RAISE_ERROR_M( RUNTIME_EXCEPTION_ERROR_CODE, (unsigned char *) "No password separator found in authorization" ); } password_pointer = pointer + 1; /* calculates the size of both the username and the password from the diference between the various pointers */ username_size = password_pointer - authorization_d - 1; password_size = authorization_d + authorization_size - password_pointer; /* copies both the username and the password values to the apropriate internal buffers (to be used in comparision) */ memcpy(username, authorization_d, username_size); username[username_size] = '\0'; memcpy(password, password_pointer, password_size); password[password_size] = '\0'; /* processes the passwd file using the provided file path for it, this is an expensive io driven operation, and must be used wth care */ process_passwd_file(auth_file, &passwd); /* retrieves the password verification value for the retrieved username and in case it's valid compares it and sets the result value accordingly */ get_value_string_hash_map( passwd, (unsigned char *) username, (void **) &password_v ); if(password_v != NULL && strcmp(password, password_v) == 0) { *result = TRUE; } else { *result = FALSE; } /* releases the memory associated with the complete set of values in the passwd structure and then releases the memory from the hash map structure itself, then releases the memory associated with the authorization decoded string */ delete_values_hash_map(passwd); delete_hash_map(passwd); FREE(authorization_d); /* raises no error, as everything has been done as possible with no problems created in the processing */ RAISE_NO_ERROR; }
ERROR_CODE _send_response_handler_lua(struct http_parser_t *http_parser) { /* retrieves the connection from the HTTP parser parameters */ struct connection_t *connection = (struct connection_t *) http_parser->parameters; /* retrieves the HTTP connection from the io connection and uses it to retrieve the correct (mod Lua) handler to operate around it */ struct http_connection_t *http_connection = (struct http_connection_t *) ((struct io_connection_t *) connection->lower)->lower; struct mod_lua_http_handler_t *mod_lua_http_handler = (struct mod_lua_http_handler_t *) http_connection->http_handler->lower; /* allocates space for the result code */ ERROR_CODE result_code; /* acquires the lock on the HTTP connection, this will avoids further messages to be processed, no parallel request handling problems */ http_connection->acquire(http_connection); /* in case the Lua state is not started an error must have occured so need to return immediately in error */ if(mod_lua_http_handler->lua_state == NULL) { /* writes the error to the connection and then returns in error to the caller function */ _write_error_connection_lua(http_parser, "no Lua state available"); RAISE_ERROR_M(RUNTIME_EXCEPTION_ERROR_CODE, (unsigned char *) "Problem accessing Lua state"); } /* registers the current connection in Lua */ lua_pushlightuserdata(mod_lua_http_handler->lua_state, (void *) http_parser); lua_setglobal(mod_lua_http_handler->lua_state, "connection"); /* registers the write connection function in Lua */ lua_register(mod_lua_http_handler->lua_state, "write_connection", _lua_write_connection); /* runs the script in case the current file is considered to be dirty, this is the case for the loading of the module and reloading*/ if(mod_lua_http_handler->file_dirty) { result_code = luaL_dofile(mod_lua_http_handler->lua_state, mod_lua_http_handler->file_path); mod_lua_http_handler->file_dirty = 0; } else { result_code = 0; } /* in case there was an error in Lua */ if(LUA_ERROR(result_code)) { /* retrieves the error message and then writes it to the connection so that the end user may be able to respond to it */ char *error_message = (char *) lua_tostring(mod_lua_http_handler->lua_state, -1); _write_error_connection_lua(http_parser, error_message); /* sets the file as dirty (forces reload) and then reloads the curernt internal Lua state, virtual machine reset (to avoid corruption) */ mod_lua_http_handler->file_dirty = 1; _reload_lua_state(&mod_lua_http_handler->lua_state); /* prints a warning message, closes the Lua interpreter and then raises the error to the upper levels */ V_WARNING_F("There was a problem executing: %s\n", mod_lua_http_handler->file_path); RAISE_ERROR_M(RUNTIME_EXCEPTION_ERROR_CODE, (unsigned char *) "Problem executing script file"); } /* retrieves the field reference to the handle method that symbol to call the function (in protected mode) and retrieves the result */ lua_getfield(mod_lua_http_handler->lua_state, LUA_GLOBALSINDEX, "handle"); result_code = lua_pcall(mod_lua_http_handler->lua_state, 0, 0, 0); /* in case there was an error in Lua */ if(LUA_ERROR(result_code)) { /* retrieves the error message and then writes it to the connection so that the end user may be able to respond to it */ char *error_message = (char *) lua_tostring(mod_lua_http_handler->lua_state, -1); _write_error_connection_lua(http_parser, error_message); /* sets the file reference as dirty, this will force the script file to be reload on next request */ mod_lua_http_handler->file_dirty = 1; /* prints a warning message, closes the Lua interpreter and then raises the error to the upper levels */ V_WARNING_F("There was a problem running call on file: %s\n", mod_lua_http_handler->file_path); RAISE_ERROR_M(RUNTIME_EXCEPTION_ERROR_CODE, (unsigned char *) "Problem calling the handle method"); } /* raise no error */ RAISE_NO_ERROR; }