#include #include #include #include #define SUCCESS 0 #define FAILURE 1 #define FALSE 0 #define TRUE 1 typedef struct post_data_node { char *variable; // variable is always NULL terminated char *value; // value IS always NULL terminated. char *file_data; // binary file upload. NOT NULL Terminated! Length determined by file_length (below) uint64_t file_length; // specifies the length (in bytes) of file struct post_data_node *next; } post_data_node; char * html_escape_string (char *); post_data_node * retrieve_post_data (char *); post_data_node * add_post_data_to_list (post_data_node *, char *, char *, char *, uint64_t); int is_valid_unsigned_integer (char *); uint64_t convert_ascii_base10_to_unsigned_64bit_integer (char *); char * decode_url_string (char *); int main (int argc, char *argv[]) { post_data_node *post_data_list_head, *temp_post_data_element; char *safe_html_string; post_data_list_head = NULL; if (getenv("CONTENT_LENGTH") != NULL) { post_data_list_head = retrieve_post_data (getenv("CONTENT_LENGTH")); } printf ("Content-type: text/html\n\n"); temp_post_data_element = post_data_list_head; if (temp_post_data_element != NULL) { printf ("\n"); printf ("\n"); printf (" \n"); printf (" POST form data results\n"); printf (" \n"); printf (" \n"); printf ("

The following form data was received in a POST request:

\n"); printf (" \n"); printf (" \n"); printf (" \n"); printf (" \n"); printf (" \n"); while (temp_post_data_element != NULL) { if ((temp_post_data_element->variable != NULL) && (temp_post_data_element->value != NULL)) { printf (" \n"); safe_html_string = html_escape_string (temp_post_data_element->variable); if (safe_html_string != NULL) { printf (" \n", safe_html_string); free (safe_html_string); } else { printf (" \n"); } safe_html_string = html_escape_string (temp_post_data_element->value); if (safe_html_string != NULL) { printf (" \n", safe_html_string); free (safe_html_string); } else { printf (" \n"); } printf (" \n"); } temp_post_data_element = temp_post_data_element->next; } } else { printf ("\n"); printf ("\n"); printf (" \n"); printf (" New user registration\n"); printf (" \n"); printf (" \n"); printf (" \n"); printf ("

Username:

\n"); printf ("

Password:

\n"); printf ("

Confirm password:

\n"); printf ("

\n"); printf (" \n"); printf (" \n"); printf ("\n"); } while (post_data_list_head != NULL) { temp_post_data_element = post_data_list_head; post_data_list_head = post_data_list_head->next; free (temp_post_data_element); } exit (SUCCESS); } char * html_escape_string (char *input_string) { char *web_safe_output_string, *byte, temp_string[10]; uint64_t output_string_length; web_safe_output_string = NULL; if (input_string != NULL) { output_string_length = 0; byte = input_string; while (*byte != '\0') { if ((*byte == '"') || (*byte =='\'') || (*byte == '&') || (*byte == '<') || (*byte == '>')) { output_string_length = output_string_length + 5; } else { if ((*byte >= 127) && (*byte <= 255)) { output_string_length = output_string_length + 6; } else { output_string_length++; } } byte++; } if (output_string_length > 0) { web_safe_output_string = malloc(sizeof(char) * (output_string_length + 1)); if (web_safe_output_string != NULL) { *web_safe_output_string = '\0'; byte = input_string; while (*byte != '\0') { if ((*byte == '"') || (*byte =='\'') || (*byte == '&') || (*byte == '<') || (*byte == '>') || ((*byte >= 127) && (*byte <= 255))) { sprintf (temp_string, "&#%d;", *byte); } else { temp_string[0] = *byte; temp_string[1] = '\0'; } strcat (web_safe_output_string, temp_string); byte++; } } } } return web_safe_output_string; } post_data_node * retrieve_post_data (char *post_data_length_string) { char *raw_variable, *variable, *raw_value, *value, *raw_post_data, byte, *boundary_string, *file_data; uint64_t bytes_read, post_data_length, string_length_variable, string_length_value, begin, end, i, j, string_length, boundary_string_length, file_length; post_data_node *post_data_list_head; unsigned int state, match, done, is_style2_post_data_format, num_alphanumerics, num_dashes; int valid_post_data; post_data_list_head = NULL; boundary_string = NULL; raw_post_data = NULL; is_style2_post_data_format = FALSE; // // First check to make sure input string is a valid unsigned integer and not some random garbage. // The reason for doing this is to prevent possible malicious attacks. if (is_valid_unsigned_integer (post_data_length_string)) { post_data_length = convert_ascii_base10_to_unsigned_64bit_integer (post_data_length_string); if (post_data_length > 0) { raw_post_data = (char *) malloc(sizeof(char) * (post_data_length + 1)); if (raw_post_data != NULL) { bytes_read = 0; while (bytes_read < post_data_length) { raw_post_data[bytes_read] = getchar(); bytes_read++; } raw_post_data[bytes_read] = '\0'; // // post data comes in as a continuous string of variable=value pairs like this (style #1): // // session_id=123&command=search&query=this+is+my+search // // Alternately, if a file is being uploaded, we'll receive something in a format that looks like this (style #2): // // -----------------------------27462048810346577881349256922\r\n // Content-Disposition: form-data; name="video"; filename="rendered_model_preview_thumbnail.png"\r\n // Content-Type: image/png\r\n // \r\n // PNG\r\n\n\rIHDRddsRGBpHYstIME"btEXtCommentCreated with GIMPWIDATx_H_QAxUdXM"]EwAI"xxd(wKiwqL79gsuvyg=waaaaaaaaV+;JIKGvO%$))'OLMM/&$IW\I(<"bUUPv3$ES{{;H$vq7ad%Or8J`xxgDt5x\X-//y&0JUUUe6e0J$._LDUUU]f@QC_#Dt-9slwsDT^^0JVj5V}{&Hl0$>iO>|k,#e8&00$;%Eu`or(wF,L&4M[YYyltsXZZZ0_~?~o===_|z.;q^.)).Q @D~]ZZG&K;|"cdr \nQEE?^V=J7u_r_$Y&t-Y;;;-~H70P \H/HQ86UUtxsgG?\r)Z[[<~::\nkR|!02>}Z***#e~2cnnN4(J,^w!>22yF|~za%{$:00+-^w!faut/N'd2)j~+!'aaaaaaaaarWSoIENDB`\r\n // -----------------------------27462048810346577881349256922\r\n // Content-Disposition: form-data; name="submit"\r\n // \r\n // submit\r\n // -----------------------------27462048810346577881349256922\r\n // Content-Disposition: form-data; name="session_id"\r\n // \r\n8FCADC223625049991E2A13149EDAF9AE4536A81\r\n // -----------------------------27462048810346577881349256922--\r\n // // // // IPADs have a different way of posting data for style #2. Here's an example: // // ------WebKitFormBoundaryqNWzSOKBrBI03evf\r\n // Content-Disposition: form-data; name="video"; filename="trim.0A264537-DC50-460A-92A0-CAB554261AA2.MOV"\r\n // Content-Type: video/quicktime\r\n // \r\n // // The next step is to parse this string to determine if data is in format style #2: state = 0; bytes_read = 0; num_dashes = 0; num_alphanumerics = 0; done = FALSE; while ((bytes_read < post_data_length) && (!done)) { byte = raw_post_data[bytes_read]; switch (state) { case 0: if (byte == '-') { num_dashes++; state = 0; } else { if (((byte >= '0') && (byte <= '9')) || ((byte >= 'A') && (byte <= 'Z')) || ((byte >= 'a') && (byte <= 'z'))) { num_alphanumerics++; state = 1; } else { done = TRUE; } } break; case 1: if (((byte >= '0') && (byte <= '9')) || ((byte >= 'A') && (byte <= 'Z')) || ((byte >= 'a') && (byte <= 'z'))) { num_alphanumerics++; state = 1; } else { if (byte == '\r') { state = 2; } else { done = TRUE; } } break; case 2: if (byte == '\n') { if ((num_dashes > 5) && (num_alphanumerics > 5)) { is_style2_post_data_format = TRUE; } } done = TRUE; break; } if (!done) { bytes_read++; } } // // Knowing the data doesn't appear to be in style #2 post data format, go ahead and parse as style #1 format. if (!is_style2_post_data_format) { state = 0; bytes_read = 0; while (bytes_read < post_data_length) { byte = raw_post_data[bytes_read]; switch (state) { case 0: begin = bytes_read; end = 0; state = 1; break; case 1: if (byte == '=') { end = bytes_read - 1; string_length = end - begin + 1; raw_variable = (char *) malloc (sizeof(char) * (string_length + 1)); if (raw_variable != NULL) { i = 0; j = begin; while (i < string_length) { raw_variable[i] = raw_post_data[j]; i++; j++; } raw_variable[i] = '\0'; variable = decode_url_string (raw_variable); free (raw_variable); raw_variable = NULL; } state = 2; } break; case 2: if (byte != '&') { begin = bytes_read; state = 3; } else { value = NULL; post_data_list_head = add_post_data_to_list (post_data_list_head, variable, value, NULL, 0); state = 0; } break; case 3: if (byte == '&') { end = bytes_read - 1; string_length = end - begin + 1; raw_value = (char *) malloc (sizeof(char) * (string_length + 1)); if (raw_value != NULL) { i = 0; j = begin; while (i < string_length) { raw_value[i] = raw_post_data[j]; i++; j++; } raw_value[i] = '\0'; value = decode_url_string (raw_value); post_data_list_head = add_post_data_to_list (post_data_list_head, variable, value, NULL, 0); free (raw_value); raw_value = NULL; state = 0; } } break; } bytes_read++; if ((state == 3) && (bytes_read == post_data_length)) { end = bytes_read - 1; string_length = end - begin + 1; raw_value = (char *) malloc (sizeof(char) * (string_length + 1)); if (raw_value != NULL) { i = 0; j = begin; while (i < string_length) { raw_value[i] = raw_post_data[j]; i++; j++; } raw_value[i] = '\0'; value = decode_url_string (raw_value); post_data_list_head = add_post_data_to_list (post_data_list_head, variable, value, NULL, 0); free (raw_value); raw_value = NULL; } } } } // // Parse the data as style #2 post data format. if (is_style2_post_data_format) { done = FALSE; state = 0; bytes_read = 0; while ((bytes_read < post_data_length) && (!done)) { byte = raw_post_data[bytes_read]; switch (state) { case 0: begin = 0; end = 0; if (byte == '-') { begin = bytes_read; state = 1; } else { done = TRUE; } break; case 1: if (byte == '-') { state = 1; } else { if (((byte >= '0') && (byte <= '9')) || ((byte >= 'A') && (byte <= 'Z')) || ((byte >= 'a') && (byte <= 'z'))) { state = 2; } else { done = TRUE; } } break; case 2: if (((byte >= '0') && (byte <= '9')) || ((byte >= 'A') && (byte <= 'Z')) || ((byte >= 'a') && (byte <= 'z'))) { state = 2; } else { if (byte == '\r') { end = bytes_read - 1; state = 3; } else { done = TRUE; } } break; case 3: if (byte == '\n') { state = 4; } else { done = TRUE; } break; case 4: boundary_string_length = end - begin + 1; boundary_string = (char *) malloc (sizeof(char) * (boundary_string_length + 1)); if (boundary_string != NULL) { i = 0; j = begin; while (i < boundary_string_length) { boundary_string[i] = raw_post_data[j]; i++; j++; } boundary_string[i] = '\0'; if (byte == 'C') { state = 5; } else { done = TRUE; } } else { done = TRUE; } break; case 5: if (byte == 'o') // Co { state = 6; } else { done = TRUE; } break; case 6: if (byte == 'n') // Con { state = 7; } else { done = TRUE; } break; case 7: if (byte == 't') // Cont { state = 8; } else { done = TRUE; } break; case 8: if (byte == 'e') // Conte { state = 9; } else { done = TRUE; } break; case 9: if (byte == 'n') // Conten { state = 10; } else { done = TRUE; } break; case 10: if (byte == 't') // Content { state = 11; } else { done = TRUE; } break; case 11: if (byte == '-') // Content- { state = 12; } else { done = TRUE; } break; case 12: if (byte == 'D') // Content-D { state = 13; } else { done = TRUE; } break; case 13: if (byte == 'i') // Content-Di { state = 14; } else { done = TRUE; } break; case 14: if (byte == 's') // Content-Dis { state = 15; } else { done = TRUE; } break; case 15: if (byte == 'p') // Content-Disp { state = 16; } else { done = TRUE; } break; case 16: if (byte == 'o') // Content-Dispo { state = 17; } else { done = TRUE; } break; case 17: if (byte == 's') // Content-Dispos { state = 18; } else { done = TRUE; } break; case 18: if (byte == 'i') // Content-Disposi { state = 19; } else { done = TRUE; } break; case 19: if (byte == 't') // Content-Disposit { state = 20; } else { done = TRUE; } break; case 20: if (byte == 'i') // Content-Dispositi { state = 21; } else { done = TRUE; } break; case 21: if (byte == 'o') // Content-Dispositio { state = 22; } else { done = TRUE; } break; case 22: if (byte == 'n') // Content-Disposition { state = 23; } else { done = TRUE; } break; case 23: if (byte == ':') // Content-Disposition: { state = 24; } else { done = TRUE; } break; case 24: if (byte == ' ') // Content-Disposition: { state = 25; } else { done = TRUE; } break; case 25: if (byte == 'f') // Content-Disposition: f { state = 26; } else { done = TRUE; } break; case 26: if (byte == 'o') // Content-Disposition: fo { state = 27; } else { done = TRUE; } break; case 27: if (byte == 'r') // Content-Disposition: for { state = 28; } else { done = TRUE; } break; case 28: if (byte == 'm') // Content-Disposition: form { state = 29; } else { done = TRUE; } break; case 29: if (byte == '-') // Content-Disposition: form- { state = 30; } else { done = TRUE; } break; case 30: if (byte == 'd') // Content-Disposition: form-d { state = 31; } else { done = TRUE; } break; case 31: if (byte == 'a') // Content-Disposition: form-da { state = 32; } else { done = TRUE; } break; case 32: if (byte == 't') // Content-Disposition: form-dat { state = 33; } else { done = TRUE; } break; case 33: if (byte == 'a') // Content-Disposition: form-data { state = 34; } else { done = TRUE; } break; case 34: if (byte == ';') // Content-Disposition: form-data; { state = 35; } else { done = TRUE; } break; case 35: if (byte == ' ') // Content-Disposition: form-data; { state = 36; } else { done = TRUE; } break; case 36: if (byte == 'n') // Content-Disposition: form-data; n { state = 37; } else { done = TRUE; } break; case 37: if (byte == 'a') // Content-Disposition: form-data; na { state = 38; } else { done = TRUE; } break; case 38: if (byte == 'm') // Content-Disposition: form-data; nam { state = 39; } else { done = TRUE; } break; case 39: if (byte == 'e') // Content-Disposition: form-data; name { state = 40; } else { done = TRUE; } break; case 40: if (byte == '=') // Content-Disposition: form-data; name= { state = 41; } else { done = TRUE; } break; case 41: if (byte == '"') // Content-Disposition: form-data; name=" { state = 42; } else { done = TRUE; } break; case 42: if (byte != '"') // Content-Disposition: form-data; name=" { begin = bytes_read; state = 43; } else { done = TRUE; } break; case 43: if (byte != '"') // Content-Disposition: form-data; name="....... { state = 43; } else { end = bytes_read - 1; string_length = end - begin + 1; variable = (char *) malloc (sizeof(char) * (string_length + 1)); // 1 extra byte reserved for null terminator if (variable != NULL) { i = 0; j = begin; while (i < string_length) { variable[i] = raw_post_data[j]; i++; j++; } variable[i] = '\0'; state = 44; } else { done = TRUE; } } break; case 44: if (byte == ';') // Content-Disposition: form-data; name="......."; { state = 45; } else { if (byte == '\r') // Content-Disposition: form-data; name="......."\r { state = 80; } else { done = TRUE; } } break; case 45: if (byte == ' ') // Content-Disposition: form-data; name="......."; { state = 46; } else { done = TRUE; } break; case 46: if (byte == 'f') // Content-Disposition: form-data; name="......."; f { state = 47; } else { if (byte == '\r') // Content-Disposition: form-data; name=".......";\r { state = 80; } else { done = TRUE; } } break; case 47: if (byte == 'i') // Content-Disposition: form-data; name="......."; fi { state = 48; } else { done = TRUE; } break; case 48: if (byte == 'l') // Content-Disposition: form-data; name="......."; fil { state = 49; } else { done = TRUE; } break; case 49: if (byte == 'e') // Content-Disposition: form-data; name="......."; file { state = 50; } else { done = TRUE; } break; case 50: if (byte == 'n') // Content-Disposition: form-data; name="......."; filen { state = 51; } else { done = TRUE; } break; case 51: if (byte == 'a') // Content-Disposition: form-data; name="......."; filena { state = 52; } else { done = TRUE; } break; case 52: if (byte == 'm') // Content-Disposition: form-data; name="......."; filenam { state = 53; } else { done = TRUE; } break; case 53: if (byte == 'e') // Content-Disposition: form-data; name="......."; filename { state = 54; } else { done = TRUE; } break; case 54: if (byte == '=') // Content-Disposition: form-data; name="......."; filename= { state = 55; } else { done = TRUE; } break; case 55: if (byte == '"') // Content-Disposition: form-data; name="......."; filename=" { state = 56; } else { done = TRUE; } break; case 56: begin = bytes_read; if (byte != '"') // Content-Disposition: form-data; name="......."; filename="....... { state = 57; } else { if (byte == '"') { value = NULL; state = 58; } else { done = TRUE; } } break; case 57: if (byte != '"') // Content-Disposition: form-data; name="......."; filename="....... { state = 57; } else // Content-Disposition: form-data; name="......."; filename="......." { end = bytes_read - 1; string_length = end - begin + 1; value = (char *) malloc (sizeof(char) * (string_length + 1)); // 1 extra byte reserved for null terminator if (value != NULL) { i = 0; j = begin; while (i < string_length) { value[i] = raw_post_data[j]; i++; j++; } value[i] = '\0'; state = 58; } else { done = TRUE; } } break; case 58: if (byte == '\r') // Content-Disposition: form-data; name="......."; filename="......."\r { state = 59; } else { done = TRUE; } break; case 59: if (byte == '\n') // Content-Disposition: form-data; name="......."; filename="......."\r\n { state = 60; } else { done = TRUE; } break; case 60: if (byte == 'C') // C { state = 61; } else { done = TRUE; } break; case 61: if (byte == 'o') // Co { state = 62; } else { done = TRUE; } break; case 62: if (byte == 'n') // Con { state = 63; } else { done = TRUE; } break; case 63: if (byte == 't') // Cont { state = 64; } else { done = TRUE; } break; case 64: if (byte == 'e') // Conte { state = 65; } else { done = TRUE; } break; case 65: if (byte == 'n') // Conten { state = 66; } else { done = TRUE; } break; case 66: if (byte == 't') // Content { state = 67; } else { done = TRUE; } break; case 67: if (byte == '-') // Content- { state = 68; } else { done = TRUE; } break; case 68: if (byte == 'T') // Content-T { state = 69; } else { done = TRUE; } break; case 69: if (byte == 'y') // Content-Ty { state = 70; } else { done = TRUE; } break; case 70: if (byte == 'p') // Content-Typ { state = 71; } else { done = TRUE; } break; case 71: if (byte == 'e') // Content-Type { state = 72; } else { done = TRUE; } break; case 72: if (byte == ':') // Content-Type: { state = 73; } else { done = TRUE; } break; case 73: if (byte == ' ') // Content-Type: { state = 74; } else { done = TRUE; } break; case 74: if (byte != '\r') // Content-Type: ........ { state = 74; } else { state = 75; // Content-Type: ........\r } break; case 75: if (byte == '\n') // Content-Type: ........\r\n { state = 76; } else { done = TRUE; } break; case 76: if (byte == '\r') // \r { state = 77; } else { done = TRUE; } break; case 77: if (byte == '\n') // \r\n { state = 78; } else { done = TRUE; } break; case 78: // beginning of binary data for file upload begins here. begin = bytes_read; state = 79; break; case 79: i = 0; j = bytes_read; match = TRUE; while ((i < boundary_string_length) && (j < post_data_length) && match) { if (boundary_string[i] == raw_post_data[j]) { i++; j++; } else { match = FALSE; } } if ((i == boundary_string_length) && match) { end = bytes_read - 2; // subtract 2 bytes because \r\n always follows data stream. if (end > begin) { file_length = end - begin; file_data = (char *) malloc (sizeof(char) * (file_length)); if (file_data != NULL) { i = 0; j = begin; while (i < file_length) { file_data[i] = raw_post_data[j]; i++; j++; } post_data_list_head = add_post_data_to_list (post_data_list_head, variable, value, file_data, file_length); } } bytes_read = bytes_read + boundary_string_length - 1; state = 87; } else { state = 79; } break; case 80: if (byte == '\n') // Content-Disposition: form-data; name="......."\r\n { state = 81; } else { done = TRUE; } break; case 81: if (byte == '\r') // \r { state = 82; } else { done = TRUE; } break; case 82: if (byte == '\n') // \r\n { state = 83; } else { done = TRUE; } break; case 83: begin = bytes_read; if (byte != '\r') { state = 84; } else { state = 85; } break; case 84: if (byte != '\r') // ....... { state = 84; } else { state = 85; } break; case 85: if (byte == '\n') // .......\r\n { state = 86; } else { done = TRUE; } break; case 86: i = 0; j = bytes_read; match = TRUE; while ((i < boundary_string_length) && (j < post_data_length) && match) { if (boundary_string[i] == raw_post_data[j]) { i++; j++; } else { match = FALSE; } } if ((i == boundary_string_length) && match) { end = bytes_read - 3; string_length = end - begin + 1; value = (char *) malloc (sizeof(char) * (string_length + 1)); // 1 extra byte reserved for null terminator if (value != NULL) { i = 0; j = begin; while (i < string_length) { value[i] = raw_post_data[j]; i++; j++; } value[i] = '\0'; post_data_list_head = add_post_data_to_list (post_data_list_head, variable, value, NULL, 0); bytes_read = bytes_read + boundary_string_length - 1; state = 87; } else { done = TRUE; } } else { done = TRUE; } break; case 87: if (byte == '\r') { state = 88; } else { if ((bytes_read + 3) < post_data_length) { if ((raw_post_data[bytes_read] == '-') && (raw_post_data[bytes_read + 1] == '-') && (raw_post_data[bytes_read + 2] == '\r') && (raw_post_data[bytes_read + 3] == '\n')) { done = TRUE; } } else { done = TRUE; } } break; case 88: if (byte == '\n') { state = 89; } else { done = TRUE; } break; case 89: if (byte == 'C') { state = 5; } else { done = TRUE; } break; } bytes_read++; } } free (boundary_string); free (raw_post_data); boundary_string = NULL; raw_post_data = NULL; } } } return post_data_list_head; } post_data_node * add_post_data_to_list (post_data_node *post_data_list_head, char *variable, char *value, char *file_data, uint64_t file_length) { post_data_node *new_post_data_element, *temp_post_data_element; new_post_data_element = (post_data_node *) malloc(sizeof(post_data_node)); if (new_post_data_element != NULL) { new_post_data_element->variable = variable; new_post_data_element->value = value; new_post_data_element->file_data = file_data; new_post_data_element->file_length = file_length; new_post_data_element->next = NULL; } if (post_data_list_head == NULL) { post_data_list_head = new_post_data_element; } else { temp_post_data_element = post_data_list_head; while (temp_post_data_element->next != NULL) { temp_post_data_element = temp_post_data_element->next; } temp_post_data_element->next = new_post_data_element; } return post_data_list_head; } int is_valid_unsigned_integer (char *number_string) { unsigned int state, i; int is_valid_number; is_valid_number = FALSE; state = 0; i = 0; while ((number_string[i] != '\0') && (state == 0)) { if ((number_string[i] >= '0') && (number_string[i] <= '9')) { state = 0; i++; } else { state = 1; } } if (state == 0) { is_valid_number = TRUE; } return is_valid_number; } uint64_t convert_ascii_base10_to_unsigned_64bit_integer (char *number_string) { unsigned int i; uint64_t number; i = 0; number = 0; if (number_string[i] == '-') { i++; } while (number_string[i] != '\0') { number = number * 10 + number_string[i] - '0'; i++; } return number; } char * decode_url_string (char *url_encoded_string) { char *output_string, *temp_output_string, *byte; uint64_t output_string_length; unsigned int state; output_string = NULL; if (url_encoded_string != NULL) { state = 0; byte = url_encoded_string; output_string_length = 0; while (*byte != '\0') { switch (state) { case 0: if (*byte == '%') { state = 1; } output_string_length++; break; case 1: if (((*byte >= 'a') && (*byte <= 'f')) || ((*byte >= 'A') && (*byte <= 'F')) || ((*byte >= '0') && (*byte <= '9'))) { state = 2; } else { state = 3; } break; case 2: if (((*byte >= 'a') && (*byte <= 'f')) || ((*byte >= 'A') && (*byte <= 'F')) || ((*byte >= '0') && (*byte <= '9'))) { state = 0; } else { state = 3; } break; case 3: break; } byte++; } if ((state == 0) && (output_string_length > 0)) { output_string = (unsigned char *) malloc (sizeof(unsigned char) * (output_string_length + 1)); if (output_string != NULL) { byte = url_encoded_string; temp_output_string = output_string; while (*byte != '\0') { switch (state) { case 0: if (*byte == '+') { *temp_output_string = ' '; temp_output_string++; } else { if (*byte != '%') { *temp_output_string = *byte; temp_output_string++; } else { state = 1; } } break; case 1: if ((*byte >= 'a') && (*byte <= 'f')) { *temp_output_string = *byte - 'a' + 10; state = 2; } else { if ((*byte >= 'A') && (*byte <= 'F')) { *temp_output_string = *byte - 'A' + 10; state = 2; } else { if ((*byte >= '0') && (*byte <= '9')) { *temp_output_string = *byte - '0'; state = 2; } else { state = 3; } } } break; case 2: if ((*byte >= 'a') && (*byte <= 'f')) { *temp_output_string = *temp_output_string * 16 + *byte - 'a' + 10; temp_output_string++; state = 0; } else { if ((*byte >= 'A') && (*byte <= 'F')) { *temp_output_string = *temp_output_string * 16 + *byte - 'A' + 10; temp_output_string++; state = 0; } else { if ((*byte >= '0') && (*byte <= '9')) { *temp_output_string = *temp_output_string * 16 + *byte - '0'; temp_output_string++; state = 0; } else { state = 3; } } } case 3: break; } byte++; } *temp_output_string = '\0'; } } } return output_string; }
VARIABLEVALUE
%s %s