int http_receive_request(int sockfd, struct HttpRequest **received_request) { debug("http_receive_request"); *received_request = NULL; char *method = NULL; char *resource = NULL; struct dict *headers = dict_create(); int content_length = -1; char *payload = NULL; int http_error = HTTP_SUCCESS; char *line = NULL; if ((http_error = http_read_line(sockfd, &line)) != HTTP_SUCCESS) { goto error; } if ((http_error = http_parse_request_line(line, &method, &resource)) != HTTP_SUCCESS) { goto error; } free(line); if ((http_error = http_receive_headers(sockfd, headers)) != HTTP_SUCCESS) { goto error; } const char *l = dict_get_case(headers, "Content-Length"); if (l != 0) { content_length = atoi(l); } if (content_length == -1 || content_length == 0) { debug("No or 0 content-length."); content_length = 0; } else { if ((http_error = http_receive_payload(sockfd, &payload, content_length)) != HTTP_SUCCESS) { goto error; } } // create and fill return object struct HttpRequest *request = (struct HttpRequest *)malloc(sizeof(struct HttpRequest)); check_mem(request); request->method = method; request->resource = resource; request->headers = headers; request->content_length = content_length; request->payload = payload; *received_request = request; return HTTP_SUCCESS; error: dict_free(headers); //TODO free entries free(method); free(resource); free(payload); free(line); assert(http_error != HTTP_SUCCESS); return http_error; }
const char *http_request_headers(int fd) { static char buf[8192]; /* static variables are not on the stack */ int i; char value[512]; char envvar[512]; /* For lab 2: don't remove this line. */ touch("http_request_headers"); /* Now parse HTTP headers */ for (;;) { if (http_read_line(fd, buf, sizeof(buf)) < 0) return "Socket IO error"; if (buf[0] == '\0') /* end of headers */ break; /* Parse things like "Cookie: foo bar" */ char *sp = strchr(buf, ' '); if (!sp) return "Header parse error (1)"; *sp = '\0'; sp++; /* Strip off the colon, making sure it's there */ if (strlen(buf) == 0) return "Header parse error (2)"; char *colon = &buf[strlen(buf) - 1]; if (*colon != ':') return "Header parse error (3)"; *colon = '\0'; /* Set the header name to uppercase and replace hyphens with underscores */ for (i = 0; i < strlen(buf); i++) { buf[i] = toupper(buf[i]); if (buf[i] == '-') buf[i] = '_'; } /* Decode URL escape sequences in the value */ url_decode(value, sp); /* Store header in env. variable for application code */ /* Some special headers don't use the HTTP_ prefix. */ if (strcmp(buf, "CONTENT_TYPE") != 0 && strcmp(buf, "CONTENT_LENGTH") != 0) { sprintf(envvar, "HTTP_%s", buf); setenv(envvar, value, 1); } else { setenv(buf, value, 1); } } return 0; }
const char *http_request_line(int fd, char *reqpath, char *env, size_t *env_len) { static char buf[8192]; /* static variables are not on the stack */ char *sp1, *sp2, *qp, *envp = env; if (http_read_line(fd, buf, sizeof(buf)) < 0) return "Socket IO error"; /* Parse request like "GET /foo.html HTTP/1.0" */ sp1 = strchr(buf, ' '); if (!sp1) return "Cannot parse HTTP request (1)"; *sp1 = '\0'; sp1++; if (*sp1 != '/') return "Bad request path"; sp2 = strchr(sp1, ' '); if (!sp2) return "Cannot parse HTTP request (2)"; *sp2 = '\0'; sp2++; /* We only support GET and POST requests */ if (strcmp(buf, "GET") && strcmp(buf, "POST")) return "Unsupported request (not GET or POST)"; envp += sprintf(envp, "REQUEST_METHOD=%s", buf) + 1; envp += sprintf(envp, "SERVER_PROTOCOL=%s", sp2) + 1; /* parse out query string, e.g. "foo.py?user=bob" */ if ((qp = strchr(sp1, '?'))) { *qp = '\0'; envp += sprintf(envp, "QUERY_STRING=%s", qp + 1) + 1; } /* decode URL escape sequences in the requested path into reqpath */ url_decode(reqpath, sp1); envp += sprintf(envp, "REQUEST_URI=%s", reqpath) + 1; envp += sprintf(envp, "SERVER_NAME=zoobar.org") + 1; *envp = 0; *env_len = envp - env + 1; printf("Buffer reqpath = "); int i = 0; for (; i < *env_len; i++) { printf("%c",env[i]); } printf("\n"); return NULL; }
int http_receive_response(int sockfd, struct HttpResponse **received_response) { debug("http_receive_response"); *received_response = NULL; int status = 0; struct dict *headers = dict_create(); int content_length = -1; char *payload = NULL; int http_error = HTTP_SUCCESS; char *line = NULL; if ((http_error = http_read_line(sockfd, &line)) != HTTP_SUCCESS) { goto error; } if ((http_error = http_parse_response_line(line, &status)) != HTTP_SUCCESS) { goto error; } free(line); if ((http_error = http_receive_headers(sockfd, headers)) != HTTP_SUCCESS) { goto error; } const char *l = dict_get_case(headers, "Content-Length"); if (l != 0) { content_length = atoi(l); } if (content_length == -1 || content_length == 0) { debug("No or 0 content-length."); content_length = 0; } else { if ((http_error = http_receive_payload(sockfd, &payload, content_length)) != HTTP_SUCCESS) { goto error; } } // create and fill return object struct HttpResponse *response = (struct HttpResponse *)malloc(sizeof(struct HttpResponse)); check_mem(response); response->status = status; response->headers = headers; response->content_length = content_length; response->payload = payload; *received_response = response; return HTTP_SUCCESS; error: free(headers); free(payload); free(line); return http_error; }
int update_radio_list(char* url) { char *buf = NULL; int peer_handle = 0; int fd; int rc; peer_handle = radio_list_update_servicer_session_open(url); if(peer_handle < 0) { return -1; } fd = open(RADIO_FN, O_WRONLY | O_CREAT | O_TRUNC, 0); if(fd < 0) { return -1; } buf = rt_malloc (512); while ( 1 ) { // read a line from the header information. rc = http_read_line(peer_handle, buf, 100); if ( rc < 0 ) break; // End of headers is a blank line. exit. if (rc == 0) break; if ((rc == 2) && (buf[0] == '\r')) break; rt_kprintf(">>%s", buf); write(fd, buf, rc); } rt_free(buf); closesocket(peer_handle); if(close(fd) == 0) { rt_kprintf("Update radio list succeed \r\n"); } return 0; }
int http_receive_headers(int sockfd, struct dict *headers) { int http_error = HTTP_SUCCESS; char *line = NULL; while (TRUE) { char *field_name; char *field_value; if ((http_error = http_read_line(sockfd, &line)) != HTTP_SUCCESS) { break; } if (strcmp(line, "") == 0) { debug("End of Http header"); break; } if ((http_error = http_parse_header_line(line, &field_name, &field_value)) != HTTP_SUCCESS) { break; } free(line); dict_set(headers, field_name, field_value); } free(line); return http_error; }
void http_serve_executable(int fd, const char *pn) { char buf[1024], headers[4096], *pheaders = headers; int pipefd[2], statusprinted = 0, ret, headerslen = 4096; pipe(pipefd); switch (fork()) { case -1: http_err(fd, 500, "fork: %s", strerror(errno)); return; case 0: dup2(fd, 0); close(fd); dup2(pipefd[1], 1); close(pipefd[0]); close(pipefd[1]); execl(pn, pn, NULL); http_err(1, 500, "execl %s: %s", pn, strerror(errno)); exit(1); default: close(pipefd[1]); while (1) { if (http_read_line(pipefd[0], buf, 1024) < 0) { http_err(fd, 500, "Premature end of script headers"); close(pipefd[0]); return; } if (!*buf) break; if (!statusprinted && strncasecmp("Status: ", buf, 8) == 0) { fdprintf(fd, "HTTP/1.1 %s\r\n%s", buf + 8, headers); statusprinted = 1; } else if (statusprinted) { fdprintf(fd, "%s\r\n", buf); } else { ret = snprintf(pheaders, headerslen, "%s\r\n", buf); pheaders += ret; headerslen -= ret; if (headerslen == 0) { http_err(fd, 500, "Too many script headers"); close(pipefd[0]); return; } } } if (statusprinted) fdprintf(fd, "\r\n"); else fdprintf(fd, "HTTP/1.0 200 OK\r\n%s\r\n", headers); while ((ret = read(pipefd[0], buf, 1024)) > 0) { write(fd, buf, ret); } close(fd); close(pipefd[0]); } }
/* * http_handle_receive() * * Work out what the request we received was, and handle it. */ void http_handle_receive(http_conn* conn, int http_instance) { int data_used, rx_code; if (conn->state == READY) { rx_code = recv(conn->fd, conn->rx_wr_pos, (HTTP_RX_BUF_SIZE - (conn->rx_wr_pos - conn->rx_buffer) -1), 0); /* * If a valid data received, take care of buffer pointer & string * termination and move on. Otherwise, we need to return and wait for more * data to arrive (until we time out). */ if(rx_code > 0) { /* Increment rx_wr_pos by the amount of data received. */ conn->rx_wr_pos += rx_code; /* Place a zero just after the data received to serve as a terminator. */ *(conn->rx_wr_pos+1) = 0; if(strstr(conn->rx_buffer, HTTP_END_OF_HEADERS)) { conn->state = PROCESS; } /* If the connection is a file upload, skip right to DATA.*/ if(conn->file_upload == 1) { conn->state = DATA; } } } if(conn->state == PROCESS) { /* * If we (think) we have valid headers, keep the connection alive a bit * longer. */ conn->activity_time = alt_nticks(); /* * Attempt to process the fundamentals of the HTTP request. We may * error out and reset if the request wasn't complete, or something * was asked from us that we can't handle. */ if (http_process_request(conn)) { fprintf(stderr, "[http_handle_receive] http_process_request failed\n"); conn->state = RESET; http_manage_connection(conn, http_instance); } /* * Step through the headers to see if there is any other useful * information about our pending transaction to extract. After that's * done, send some headers of our own back to let the client know * what's happening. Also, once all in-coming headers have been parsed * we can manage our RX buffer to prepare for the next in-coming * connection. */ while(conn->state == PROCESS) { if(http_read_line(conn)) { fprintf(stderr, "[http_handle_receive] error reading headers\n"); conn->state = RESET; http_manage_connection(conn, http_instance); break; } if(http_process_headers(conn)) { if( (conn->rx_rd_pos = strstr(conn->rx_rd_pos, HTTP_CR_LF)) ) { conn->rx_rd_pos += 2; conn->state = DATA; conn->activity_time = alt_nticks(); } else { fprintf(stderr, "[http_handle_receive] Can't find end of headers!\n"); conn->state = RESET; http_manage_connection(conn, http_instance); break; } } } /* while(conn->state == PROCESS) */ if( http_prepare_response(conn) ) { conn->state = RESET; fprintf(stderr, "[http_handle_receive] Error preparing response\n"); http_manage_connection(conn, http_instance); } /* * Manage RX Buffer: Slide any un-read data in our input buffer * down over previously-read data that can now be overwritten, and * zero-out any bytes in question at the top of our new un-read space. */ if(conn->rx_rd_pos > (conn->rx_buffer + HTTP_RX_BUF_SIZE)) { conn->rx_rd_pos = conn->rx_buffer + HTTP_RX_BUF_SIZE; } data_used = conn->rx_rd_pos - conn->rx_buffer; memmove(conn->rx_buffer,conn->rx_rd_pos,conn->rx_wr_pos-conn->rx_rd_pos); conn->rx_rd_pos = conn->rx_buffer; conn->rx_wr_pos -= data_used; memset(conn->rx_wr_pos, 0, data_used); } if (conn->state == DATA && conn->file_upload == 1 ) { /* Jump to the file_upload() function....process more received data. */ upload_field.func(conn); } }
// // This is the main HTTP client connect work. Makes the connection // and handles the protocol and reads the return headers. Needs // to leave the stream at the start of the real data. // static int shoutcast_connect(struct shoutcast_session* session, struct sockaddr_in* server, char* host_addr, const char* url) { int socket_handle; int peer_handle; int rc; char mimeBuffer[256]; int timeout = HTTP_RCV_TIMEO; if((socket_handle = socket( PF_INET, SOCK_STREAM, IPPROTO_TCP )) < 0) { rt_kprintf( "ICY: SOCKET FAILED\n" ); return -1; } /* set recv timeout option */ setsockopt(socket_handle, SOL_SOCKET, SO_RCVTIMEO, (void*)&timeout, sizeof(timeout)); peer_handle = connect( socket_handle, (struct sockaddr *) server, sizeof(*server)); if ( peer_handle < 0 ) { rt_kprintf( "ICY: CONNECT FAILED %i\n", peer_handle ); lwip_close(socket_handle); return -1; } { char *buf; rt_uint32_t length; buf = rt_malloc (512); if (*url) length = rt_snprintf(buf, 512, _shoutcast_get, url, host_addr); else length = rt_snprintf(buf, 512, _shoutcast_get, "/", host_addr); rc = send(peer_handle, buf, length, 0); rt_kprintf("SHOUTCAST request:\n%s", buf); /* release buffer */ rt_free(buf); } /* read the header information */ while ( 1 ) { // read a line from the header information. rc = http_read_line(peer_handle, mimeBuffer, 100); rt_kprintf(">>%s", mimeBuffer); if ( rc < 0 ) { lwip_close(socket_handle); return rc; } // End of headers is a blank line. exit. if (rc == 0) break; if ((rc == 2) && (mimeBuffer[0] == '\r')) break; if(strstr(mimeBuffer, "ICY")) // First line of header, contains status code. Check for an error code { rc = shoutcast_is_error_header(mimeBuffer); if(rc) { rt_kprintf("ICY: status code = %d!\n", rc); lwip_close(socket_handle); return -rc; } } if (strstr(mimeBuffer, "HTTP/1.")) { rc = http_is_error_header(mimeBuffer); if(rc) { rt_kprintf("HTTP: status code = %d!\n", rc); lwip_close(socket_handle); return -rc; } } if (strstr(mimeBuffer, "icy-name:")) { /* get name */ char* name; name = mimeBuffer + strlen("icy-name:"); session->station_name = rt_strdup(name); rt_kprintf("station name: %s\n", session->station_name); } if (strstr(mimeBuffer, "icy-br:")) { /* get bitrate */ session->bitrate = strtol(mimeBuffer + strlen("icy-br:"), RT_NULL, 10); rt_kprintf("bitrate: %d\n", session->bitrate); } if (strstr(mimeBuffer, "icy-metaint:")) { /* get metaint */ session->metaint = strtol(mimeBuffer + strlen("icy-metaint:"), RT_NULL, 10); rt_kprintf("metaint: %d\n", session->metaint); } if (strstr(mimeBuffer, "content-type:")) { /* check content-type */ if (strstr(mimeBuffer, "audio/mpeg") == RT_NULL) { rt_kprintf("ICY content is not audio/mpeg.\n"); lwip_close(socket_handle); return -1; } } if (strstr(mimeBuffer, "Content-Type:")) { /* check content-type */ if (strstr(mimeBuffer, "audio/mpeg") == RT_NULL) { rt_kprintf("ICY content is not audio/mpeg.\n"); lwip_close(socket_handle); return -1; } } } // We've sent the request, and read the headers. SockHandle is // now at the start of the main data read for a file io read. return peer_handle; }
// // This is the main HTTP client connect work. Makes the connection // and handles the protocol and reads the return headers. Needs // to leave the stream at the start of the real data. // static int http_connect(struct http_session* session, struct sockaddr_in * server, char *host_addr, const char *url) { int socket_handle; int peer_handle; int rc; char mimeBuffer[100]; int timeout = HTTP_RCV_TIMEO; if((socket_handle = socket( PF_INET, SOCK_STREAM, IPPROTO_TCP )) < 0) { rt_kprintf( "HTTP: SOCKET FAILED\n" ); return -1; } /* set recv timeout option */ setsockopt(socket_handle, SOL_SOCKET, SO_RCVTIMEO, (void*)&timeout, sizeof(timeout)); peer_handle = connect( socket_handle, (struct sockaddr *) server, sizeof(*server)); if ( peer_handle < 0 ) { rt_kprintf( "HTTP: CONNECT FAILED %i\n", peer_handle ); return -1; } { char *buf; rt_uint32_t length; buf = rt_malloc (512); if (*url) length = rt_snprintf(buf, 512, _http_get, url, host_addr); else length = rt_snprintf(buf, 512, _http_get, "/", host_addr); rc = send(peer_handle, buf, length, 0); // rt_kprintf("HTTP request:\n%s", buf); /* release buffer */ rt_free(buf); } // We now need to read the header information while ( 1 ) { int i; // read a line from the header information. rc = http_read_line( peer_handle, mimeBuffer, 100 ); // rt_kprintf(">> %s\n", mimeBuffer); if ( rc < 0 ) return rc; // End of headers is a blank line. exit. if (rc == 0) break; if ((rc == 2) && (mimeBuffer[0] == '\r')) break; // Convert mimeBuffer to upper case, so we can do string comps for(i = 0; i < strlen(mimeBuffer); i++) mimeBuffer[i] = toupper(mimeBuffer[i]); if(strstr(mimeBuffer, "HTTP/1.")) // First line of header, contains status code. Check for an error code { rc = http_is_error_header(mimeBuffer); if(rc) { rt_kprintf("HTTP: status code = %d!\n", rc); return -rc; } } if(strstr(mimeBuffer, "CONTENT-LENGTH:")) { session->size = http_parse_content_length(mimeBuffer); rt_kprintf("size = %d\n", session->size); } } // We've sent the request, and read the headers. SockHandle is // now at the start of the main data read for a file io read. return peer_handle; }
const char *http_request_line(int fd, char *reqpath, char *env, size_t *env_len, int env_buf_size, int reqpath_buf_size) { static char buf[8192]; /* static variables are not on the stack */ char *sp1, *sp2, *qp, *envp = env; /* For lab 2: don't remove this line. */ touch("http_request_line"); if (http_read_line(fd, buf, sizeof(buf)) < 0) return "Socket IO error"; /* Parse request like "GET /foo.html HTTP/1.0" */ sp1 = strchr(buf, ' '); if (!sp1) return "Cannot parse HTTP request (1)"; *sp1 = '\0'; sp1++; if (*sp1 != '/') return "Bad request path"; sp2 = strchr(sp1, ' '); if (!sp2) return "Cannot parse HTTP request (2)"; *sp2 = '\0'; sp2++; /* We only support GET and POST requests */ if (strcmp(buf, "GET") && strcmp(buf, "POST")) return "Unsupported request (not GET or POST)"; /* We start building the env, without exceeding env_buf_size Checks for REQUEST_METHOD and SERVER_NAME are optional, but I add them for consistency in case we would like to extend the code in the future. */ int copied = 0; int request_method_size = snprintf(envp, env_buf_size-copied, "REQUEST_METHOD=%s", buf); if (request_method_size >= env_buf_size-copied) return "Unsupported request method"; envp += request_method_size+1; copied += request_method_size+1; int protocol_size = snprintf(envp, env_buf_size-copied, "SERVER_PROTOCOL=%s", sp2); if (protocol_size >= env_buf_size-copied) return "Unsupported server protocol"; envp += protocol_size+1; copied += protocol_size+1; /* parse out query string, e.g. "foo.py?user=bob" */ if ((qp = strchr(sp1, '?'))) { *qp = '\0'; int query_string_size = snprintf(envp, env_buf_size-copied, "QUERY_STRING=%s", qp + 1); if (query_string_size >= env_buf_size-copied) return "Query string too long"; envp += query_string_size+1; copied += query_string_size+1; } /* decode URL escape sequences in the requested path into reqpath */ url_decode(reqpath, sp1, reqpath_buf_size); int request_uri_size = snprintf(envp, env_buf_size-copied, "REQUEST_URI=%s", reqpath); if (request_uri_size >= env_buf_size-copied) return "Request URI too long"; envp += request_uri_size+1; copied += request_uri_size+1; int server_name_size = snprintf(envp, env_buf_size-copied, "SERVER_NAME=zoobar.org"); if (server_name_size >= env_buf_size-copied) return "Request line too long"; copied += request_uri_size+1; *env_len = copied; return NULL; }
int radio_list_update_servicer_connect(struct sockaddr_in* server, char* host_addr, const char* url) { int socket_handle; int peer_handle; int rc; char mimeBuffer[256]; if((socket_handle = socket( PF_INET, SOCK_STREAM, IPPROTO_TCP )) < 0) { rt_kprintf( "RLUS: SOCKET FAILED\n" ); return -1; } peer_handle = connect( socket_handle, (struct sockaddr *) server, sizeof(*server)); if ( peer_handle < 0 ) { closesocket(socket_handle); rt_kprintf( "RLUS: CONNECT FAILED %i\n", peer_handle ); return -1; } { char *buf; rt_uint32_t length; buf = rt_malloc (512); if (*url) length = rt_snprintf(buf, 512, _radio_list_update_get, url, host_addr, ntohs(server->sin_port)); else length = rt_snprintf(buf, 512, _radio_list_update_get, "/", host_addr, ntohs(server->sin_port)); rc = send(peer_handle, buf, length, 0); rt_kprintf("radio list update request:\n%s", buf); /* release buffer */ rt_free(buf); } /* read the header information */ while ( 1 ) { // read a line from the header information. rc = http_read_line(peer_handle, mimeBuffer, 100); rt_kprintf(">>%s", mimeBuffer); if ( rc < 0 ) { closesocket(peer_handle); return rc; } // End of headers is a blank line. exit. if (rc == 0) break; if ((rc == 2) && (mimeBuffer[0] == '\r')) break; if (strstr(mimeBuffer, "HTTP/1.")) { rc = http_is_error_header(mimeBuffer); if(rc) { rt_kprintf("HTTP: status code = %d!\n", rc); closesocket(peer_handle); return -rc; } } if (strstr(mimeBuffer, "content-type:")) { /* check content-type */ if (strstr(mimeBuffer, "text/plain") == RT_NULL) { rt_kprintf("radio list update content is not text/plain.\n"); closesocket(peer_handle); return -1; } } if (strstr(mimeBuffer, "Content-Type:")) { #if 0 // not check content-type anymore /* check content-type */ if (strstr(mimeBuffer, "text/plain") == RT_NULL) { rt_kprintf("radio list update content is not text/plain.\n"); closesocket(peer_handle); return -1; } #endif } } return peer_handle; }