void worker_can_read(int fd, short event, void *p) { struct http_client *c = p; int ret, nparsed; (void)fd; (void)event; ret = http_client_read(c); if(ret <= 0) { if((client_error_t)ret == CLIENT_DISCONNECTED) { return; } else if (c->failed_alloc || (client_error_t)ret == CLIENT_OOM) { slog(c->w->s, WEBDIS_DEBUG, "503", 3); http_send_error(c, 503, "Service Unavailable"); return; } } if(c->is_websocket) { /* Got websocket data */ ws_add_data(c); } else { /* run parser */ nparsed = http_client_execute(c); if(c->failed_alloc) { slog(c->w->s, WEBDIS_DEBUG, "503", 3); http_send_error(c, 503, "Service Unavailable"); } else if(c->is_websocket) { /* we need to use the remaining (unparsed) data as the body. */ if(nparsed < ret) { http_client_add_to_body(c, c->buffer + nparsed + 1, c->sz - nparsed - 1); ws_handshake_reply(c); } else { c->broken = 1; } free(c->buffer); c->buffer = NULL; c->sz = 0; } else if(nparsed != ret) { slog(c->w->s, WEBDIS_DEBUG, "400", 3); http_send_error(c, 400, "Bad Request"); } else if(c->request_sz > c->s->cfg->http_max_request_size) { slog(c->w->s, WEBDIS_DEBUG, "413", 3); http_send_error(c, 413, "Request Entity Too Large"); } } if(c->broken) { /* terminate client */ http_client_free(c); } else { /* start monitoring input again */ worker_monitor_input(c); } }
/** * Called when a client has finished reading input and can create a cmd */ void worker_process_client(struct http_client *c) { /* check that the command can be executed */ struct worker *w = c->w; cmd_response_t ret = CMD_PARAM_ERROR; switch(c->parser.method) { case HTTP_GET: if(c->path_sz == 16 && memcmp(c->path, "/crossdomain.xml", 16) == 0) { http_crossdomain(c); return; } slog(w->s, WEBDIS_DEBUG, c->path, c->path_sz); ret = cmd_run(c->w, c, 1+c->path, c->path_sz-1, NULL, 0); break; case HTTP_POST: slog(w->s, WEBDIS_DEBUG, c->path, c->path_sz); ret = cmd_run(c->w, c, c->body, c->body_sz, NULL, 0); break; case HTTP_PUT: slog(w->s, WEBDIS_DEBUG, c->path, c->path_sz); ret = cmd_run(c->w, c, 1+c->path, c->path_sz-1, c->body, c->body_sz); break; case HTTP_OPTIONS: http_send_options(c); return; default: slog(w->s, WEBDIS_DEBUG, "405", 3); http_send_error(c, 405, "Method Not Allowed"); return; } switch(ret) { case CMD_ACL_FAIL: case CMD_PARAM_ERROR: slog(w->s, WEBDIS_DEBUG, "403", 3); http_send_error(c, 403, "Forbidden"); break; case CMD_REDIS_UNAVAIL: slog(w->s, WEBDIS_DEBUG, "503", 3); http_send_error(c, 503, "Service Unavailable"); break; default: break; } }
static int http_parse_mime(uchar *tcp_data, ushort tcp_data_len, uchar nr) { uchar *ptr; uint data_len; uint mem_len; /* skip boundary="boundary code" */ if ((ptr = (uchar *)strstr((const char *)tcp_data, boundary_code)) == NULL) return 1; else ptr = ptr + strlen(boundary_code); mem_len = tcp_data_len - (ptr - tcp_data); /* find the first boundary code */ if ((ptr = (uchar *)memstr((const char *)ptr, boundary_code, mem_len)) != NULL) { /* the first content length */ post_info.rcv_len = tcp_data_len - (ptr - tcp_data) + 2; /* move pointer to Content-Disposition */ ptr = ptr + strlen(boundary_code); /* get upload file name */ ptr = (uchar *)strstr((const char *)ptr, c_fname); ptr = (uchar *)strchr((const char *)ptr,'"'); if (*(ptr+1) == '"') { printf("No file to be uploaded !!!\n"); http_state = HTTP_START; http_send_error(nr, 400, "Bad Request", "No upload file name to be slected !"); return 1; } else { /* printf("Parsing file name...\n"); */ } } else { /*printf("Can't find the first boundary code.\n");*/ return 1; } ptr = (uchar *)strstr((const char *)ptr, c_headerend); /* "\r\n\r\n" */ ptr = ptr + strlen(c_headerend); /* upload file start pointer */ data_len = tcp_data_len - (ptr - tcp_data ); post_info.data_len = data_len; memcpy(post_info.buf, ptr, data_len); return 0; }
/* routes a request to the correct handler */ static void route_perform(http_s *h) { /* add required Serevr header */ http_set_header(h, HTTP_HEADER_SERVER, fiobj_dup(HTTP_VALUE_SERVER)); /* collect path from hash map */ fio_str_info_s tmp_i = fiobj_obj2cstr(h->path); fio_str_s tmp = FIO_STR_INIT_EXISTING(tmp_i.data, tmp_i.len, 0); fio_router_handler_fn handler = fio_router_find(&routes, fio_str_hash(&tmp), tmp); /* forward request or send error */ if (handler) { handler(h); return; } http_send_error(h, 404); }
/*------------------------------------------------------------------------ * The received header must contain the word "GET" or "POST" to be * considered a valid request. * With HTTP 1.1 where the connection is left open, the header I send * should include content length. With HTTP 1.0 you can just close the * connection after sending the page and the browser knows its done. * * The HTTP protocol specification is at http://www.w3.org/Protocols/ *------------------------------------------------------------------------ */ ushort http_server(uchar *inbuf, ushort header_len, ushort tcp_len, uchar nr, uchar resend) { static uint counter=0; uint content_length; uint data_len; uchar *ptr; uchar *tcp_data; if (http_debug == DEBUG) printf("\n\n%s************ tcp_len = %d ************%d\n", __func__,tcp_len,http_state); else if ((counter++ % 100) == 0) printf("."); /* Make sure this is a valid connection */ if (nr == NO_CONNECTION) return 0; /* Compute start of TCP data */ /* Save first 20 chars and seq number just in case * we need to re-generate page * TODO: if post, then save switch state infomation * If this is a resend, set sequence number to what it was * the last time we sent this */ if (!resend) { tcp_data = inbuf + ETHER_IP_HLEN + header_len; memcpy(conxn[nr].query, tcp_data, 20); conxn[nr].old_sequence = conxn[nr].my_sequence; } else { tcp_data = inbuf; conxn[nr].my_sequence = conxn[nr].old_sequence; } if (http_debug == DEBUG) printf("#1> http_state = %d......\n",http_state); /* Pre-porcess HTTP state change. */ switch (http_state) { case HTTP_START: if ( (strstr((const char *)tcp_data, "GET") != NULL) && ((strstr((const char *)tcp_data, "index") != NULL) || (strstr((const char *)tcp_data, "/ ") != NULL)) ) http_state = HTTP_GET; else if ( (strstr((const char *)tcp_data, "POST") != NULL) ) http_state = HTTP_POST; break; case HTTP_GET: if ( (strstr((const char *)tcp_data, "POST") != NULL) ) http_state = HTTP_POST; break; case HTTP_UPLOAD: /* process the situation of network disconnection */ if ( (strstr((const char *)tcp_data, "GET") != NULL) && ((strstr((const char *)tcp_data, "index") != NULL) || (strstr((const char *)tcp_data, "/ ") != NULL)) ) http_state = HTTP_GET; break; } switch (http_state) { case HTTP_START: break; case HTTP_GET: /* send download page to HTTP client */ http_send_ok(nr, web_page, 200, "OK"); break; case HTTP_POST: if (http_parse_post(tcp_data, &content_length)) { http_state = HTTP_START; return 1; } else { post_info.upload_len = content_length; post_info.data_len = 0; post_info.buf = (uchar *)upgrade_buffer; http_state = HTTP_HEAD_DATA; } if (http_parse_mime(tcp_data, tcp_len - header_len, nr) == 0) http_state = HTTP_UPLOAD; break; case HTTP_HEAD_DATA: post_info.rcv_len = tcp_len - header_len; if (http_check_filename(tcp_data)) { http_send_error(nr, 400, "Bad Request", "No upload file name to be slected !"); http_state = HTTP_START; return 1; } ptr = (uchar *)strstr((const char *)tcp_data, c_headerend); ptr = ptr + strlen(c_headerend); /* upload file start pointer */ data_len = tcp_len - header_len - (ptr - tcp_data ); post_info.data_len = data_len; memcpy(post_info.buf, ptr, data_len); http_state = HTTP_UPLOAD; break; case HTTP_UPLOAD: post_info.rcv_len += tcp_len - header_len; if (http_debug == DEBUG) { printf("post_info.rcv_len=%d post_info.upload_len=%d\n" ,post_info.rcv_len,post_info.upload_len); } if (post_info.rcv_len >= post_info.upload_len) { /* To check the last packet if contains image data. */ /* 6-byte include two "--" and one \r\n */ /* 8-byte include two "--" and two \r\n */ if ((tcp_len - header_len) > (strlen(boundary_code)+6)) data_len = tcp_len - header_len - \ strlen(boundary_code) - 8; else data_len = 0; if (http_check_image(post_info.buf, post_info.data_len)) { http_send_error(nr, 400, "Bad Request", "File format is invalid !"); http_state = HTTP_START; return (1); } else { memset(text, 0x00, sizeof(text)); #ifdef CONFIG_MTD_CORTINA_CS752X_NAND sprintf(text,"%d", 5 + post_info.data_len/(1024*1000)); #else sprintf(text,"%d", 10 + post_info.data_len/(1024*100)); #endif replace_tag((uchar *)upgrade200_1, "TAG:NUM1", text); http_send_ok(nr, upgrade200_1, 200, "OK"); if (do_upgrade_image(post_info.buf, post_info.data_len)) { http_state = HTTP_START; return 0; } else { http_state = HTTP_REBOOT; break; } } } else { data_len = tcp_len - header_len; memcpy((void *)&post_info.buf[post_info.data_len], tcp_data, data_len); post_info.data_len += data_len; } break; case HTTP_REBOOT: if ( (strstr((const char *)tcp_data, "GET") != NULL) && (strstr((const char *)tcp_data, "reboot") != NULL) ) { http_state = HTTP_START; http_send_ok(nr, reboot200, 200, "OK"); /* * Reserved time for tx those packets that queue * in packet buffer before system reset. */ udelay(500); do_reset(NULL, 0, 0, NULL); } break; default: printf("HTTP State Error ! %d\n", http_state); break; } if (http_debug == DEBUG) printf("#2> http_state = %d......\n",http_state); return 0; }
/** * Called when a client has finished reading input and can create a cmd */ void worker_process_client(struct http_client *c) { /* check that the command can be executed */ struct worker *w = c->w; cmd_response_t ret = CMD_PARAM_ERROR; char *client_ip; /* well set this equal to the IP string address returned by inet_ntoa */ client_ip = inet_ntoa(*(struct in_addr *)&c->addr); /* cast x as a struct in_addr */ char msg[128] = {}; sprintf(msg,"%s %s",client_ip,c->path); switch(c->parser.method) { case HTTP_GET: if(c->path_sz == 16 && memcmp(c->path, "/crossdomain.xml", 16) == 0) { http_crossdomain(c); return; } ret = cmd_run(c->w, c, 1+c->path, c->path_sz-1, NULL, 0); sprintf(msg,"%s GET %d",msg,(int)ret); slog(w->s, WEBDIS_DEBUG, msg, strlen(msg)); break; case HTTP_POST: ret = cmd_run(c->w, c, c->body, c->body_sz, NULL, 0); sprintf(msg,"%s POST %d",msg,(int)ret); slog(w->s, WEBDIS_DEBUG, msg, strlen(msg)); break; case HTTP_PUT: ret = cmd_run(c->w, c, 1+c->path, c->path_sz-1, c->body, c->body_sz); sprintf(msg,"%s PUT %d",msg,(int)ret); slog(w->s, WEBDIS_DEBUG, msg, strlen(msg)); break; case HTTP_OPTIONS: http_send_options(c); default: slog(w->s, WEBDIS_DEBUG, "405", 3); http_send_error(c, 405, "Method Not Allowed"); return; } switch(ret) { case CMD_ACL_FAIL: case CMD_PARAM_ERROR: slog(w->s, WEBDIS_DEBUG, "403", 3); http_send_error(c, 403, "Forbidden"); break; case CMD_REDIS_UNAVAIL: slog(w->s, WEBDIS_DEBUG, "503", 3); http_send_error(c, 503, "Service Unavailable"); break; default: break; } }