static int ht_headers(struct channel *ch, struct buffer *bu, struct env *env) { struct headers_state hs; char name_str[80]; char value_str[2048]; struct buffer name = buffer_wrap(name_str); struct buffer value = buffer_wrap(value_str); buffer_reset(&name); buffer_reset(&value); env_init(env); hs_init(&hs); while (!ch_fill(ch)) { if (headers_parse(bu, &hs, &name, &value, env)) { ch_close(ch); return -1; } if (hs.done) break; } return 0; }
void run (int worker_id, int sock_fd, struct sockaddr addr, socklen_t addr_len) { headers_parse (sock_fd); if (headers_is_error (headers_get_state ()) || !headers_has_request()) { goto hangup; } char *name = get_request (1); char *strip = name; char response_buffer[255]; while (*strip == '.' || *strip == '/') strip++; if (!*strip) { fprintf (stderr, "%s: No such file or directory\n", name); goto _404; } int len = strlen (strip); int file_fd; char *file = malloc (2 + len + 1); file[0] = '.'; file[1] = '/'; memcpy (file + 2, strip, len); file[len + 2] = 0; file_fd = open (file, O_RDONLY); free (file); struct stat info; if (file_fd == -1 || fstat (file_fd, &info)) { if (file_fd > 0) { close (file_fd); } file_fd = 0; perror (name); goto _404; } response_init (200); char content_length[25]; sprintf (content_length, "%d", info.st_size); response_add ("Content-Length", content_length); if (write_headers (sock_fd)) { close (file_fd); goto _404; } len = read (file_fd, response_buffer, 255); while (len > 0) { if (write (sock_fd, response_buffer, len) < 0) { perror ("write"); break; } len = read (file_fd, response_buffer, 255); } if (file_fd > 0) { close (file_fd); } goto hangup; _404: response_init (404); write_headers (sock_fd); snprintf (response_buffer, 255, "File not found: '%s'\n", name); if (write (sock_fd, response_buffer, strlen (response_buffer)) < 0) { goto hangup; } goto hangup; hangup: headers_cleanup (); hangup (sock_fd); }
connection_t* connection_create( website_t* website, int sockfd, char* raw, size_t size ) { connection_t* connection = connection_init(); connection->website = website; connection->sockfd = sockfd; char* ptr,* tmp,* start = raw, urlbuf[ sizeof( connection->request.full_url ) ]; memcpy( &connection->ip, raw, sizeof( connection->ip ) ); raw += sizeof( connection->ip ); strncpy( connection->hostname, raw, sizeof( connection->hostname ) ); raw += strlen( raw ) + 1; // type ///////////////////////////////// if ( startswith( raw, HTTP_GET ) ) { connection->request.type = HTTP_GET_TYPE; raw += strlen( HTTP_GET ); } else if ( startswith( raw, HTTP_POST ) ) { connection->request.type = HTTP_POST_TYPE; raw += strlen( HTTP_POST ); } else goto fail; raw++; // skip over space //////////////////////////////////////// // url ///////////////////////////////// if ( !( tmp = strstr( raw, HTTP_HDR_ENDL ) ) ) goto fail; if ( !( ptr = strnstr( raw, "?", ( tmp - raw ) ) ) && !( ptr = strnstr( raw, " ", ( tmp - raw ) ) ) ) goto fail; url_decode( urlbuf, raw, ptr - raw ); normalize_path( connection->request.full_url, urlbuf ); while ( startswith( connection->request.full_url, "../" ) ) { strcpy( urlbuf, connection->request.full_url + 3 ); strcpy( connection->request.full_url, urlbuf ); } // Skip over websites leading url. // if website is "example.com/test/" and url is "/test/hi" "/test" gets removed connection->request.url = strchr( connection->website->url, '/' ); if ( connection->request.url ) connection->request.url = &connection->request.full_url[ ( connection->website->url + strlen( connection->website->url ) ) - connection->request.url ]; else connection->request.url = connection->request.full_url; if ( *connection->request.url == '/' ) connection->request.url++; //////////////////////////////////////// // parse qstring params //////////////// tmp = strstr( raw, HTTP_HDR_ENDL ); if ( ptr[ 0 ] == '?' ) { raw = ptr + 1; if ( !( ptr = strnstr( raw, " ", tmp - raw ) ) ) goto fail; params_parse_qs( &connection->request.params, raw, ptr - raw, PARAM_TYPE_GET ); } raw = ptr + 1; //////////////////////////////////////// // version ///////////////////////////// if ( !startswith( raw, "HTTP/" ) ) goto fail; raw += 5; // skips "HTTP/" if ( !( ptr = strstr( raw, HTTP_HDR_ENDL ) ) ) goto fail; strncpy( connection->http_version, raw, SMALLEST( ptr - raw, sizeof( connection->http_version ) - 1 ) ); connection->http_version[ SMALLEST( ptr - raw, sizeof( connection->http_version ) - 1 ) ] = '\0'; raw = ptr + strlen( HTTP_HDR_ENDL ); //////////////////////////////////////// // headers ///////////////////////////// connection->request.headers = headers_parse( raw ); //////////////////////////////////////// // cookies ///////////////////////////// header_t* header = headers_get_header( &connection->request.headers, "Cookie" ); if ( header ) connection->cookies = cookies_parse( header->value ); else connection->cookies = cookies_parse( "" ); //////////////////////////////////////// // body //////////////////////////////// if ( ( connection->request.type == HTTP_POST_TYPE ) && ( ptr = strstr( raw, HTTP_HDR_ENDL HTTP_HDR_ENDL ) ) != NULL ) { ptr += strlen( HTTP_HDR_ENDL HTTP_HDR_ENDL ); header_t* header = headers_get_header( &connection->request.headers, "Content-Type" ); char boundary[HEADER_VALUE_MAX_LEN] = "",* boundary_ptr = NULL; if ( website_options_get( website, WS_OPTION_PARSE_MULTIPARTS ) && header && startswith( headers_get_header_attr( header, NULL ), "multipart" ) && ( boundary_ptr = headers_get_header_attr( header, "boundary" ) ) ) { printf("parsing multiparts: %d\n", website->options ); strcat( boundary, "--" ); strcat( boundary, boundary_ptr ); int i = -1; if ( startswith( ptr, boundary ) ) { ptr += strlen( boundary ) + strlen( HTTP_HDR_ENDL ); while ( ( boundary_ptr = strstr( ptr, boundary ) ) ) { connection->request.parts[++i] = (request_t*) malloc( sizeof( request_t ) ); memset( connection->request.parts[i], 0, sizeof( request_t ) ); connection->request.parts[i]->headers = headers_parse( ptr ); connection->request.parts[i]->post_body = NULL; if ( !( ptr = strstr( ptr, HTTP_HDR_ENDL HTTP_HDR_ENDL ) ) ) break; ptr += sizeof( HTTP_HDR_ENDL HTTP_HDR_ENDL ) - 1; connection->request.parts[i]->post_body_len = ( boundary_ptr - ptr ) - strlen( HTTP_HDR_ENDL ); connection->request.parts[i]->post_body = (char*) malloc( connection->request.parts[i]->post_body_len + 1 ); memset( connection->request.parts[i]->post_body, 0, connection->request.parts[i]->post_body_len + 1 ); strncpy(connection->request.parts[i]->post_body, ptr, connection->request.parts[i]->post_body_len ); char* charset; header = headers_get_header( &connection->request.parts[i]->headers, "Content-Type" ); if ( header && ( charset = headers_get_header_attr( header, "charset" ) ) ) strcpy( connection->request.parts[i]->charset, charset ); else // ISO-8859-1 is the default charset for http defined by RFC strcpy( connection->request.parts[i]->charset, "ISO-8859-1" ); ptr = boundary_ptr + strlen( boundary ); if ( startswith( ptr, "--" HTTP_HDR_ENDL ) || i >= CONN_MAX_HTTP_MULTIPART ) break; ptr += strlen( HTTP_HDR_ENDL ); } if ( header && strcmp( headers_get_header_attr( header, NULL ), "multipart/form-data" ) == 0 ) params_parse_multiparts( &connection->request.params, connection->request.parts, PARAM_TYPE_POST ); } } else { connection->request.post_body_len = size - (long) ( ptr - start ); connection->request.post_body = (char*) malloc( connection->request.post_body_len + 1 ); memset( connection->request.post_body, 0, connection->request.post_body_len + 1 ); strncpy( connection->request.post_body, ptr, connection->request.post_body_len ); if ( header && strcmp( headers_get_header_attr( header, NULL ), "application/x-www-form-urlencoded" ) == 0 ) params_parse_qs( &connection->request.params, connection->request.post_body, connection->request.post_body_len, PARAM_TYPE_POST ); } char* charset; header = headers_get_header( &connection->request.headers, "Content-Type" ); if ( header && ( charset = headers_get_header_attr( header, "charset" ) ) ) strcpy( connection->request.charset, charset ); else // ISO-8859-1 is the default charset for http defined by RFC strcpy( connection->request.charset, "ISO-8859-1" ); } //////////////////////////////////////// return connection; fail: connection_free( connection ); return NULL; }