/* Send one chunk of data of a given size */ int httpd_send_chunk(int conn, const char *buf, int len) { int err; if (len) { /* Send chunk begin header */ err = httpd_send_chunk_begin(conn, len); if (err != WM_SUCCESS) return err; /* Send our data */ err = httpd_send(conn, buf, len); if (err != WM_SUCCESS) return err; /* Send chunk end indicator */ err = httpd_send_crlf(conn); if (err != WM_SUCCESS) return err; } else { /* Length is 0, last chunk */ err = httpd_send(conn, http_last_chunk, sizeof(http_last_chunk) - 1); if (err != WM_SUCCESS) return err; } return err; }
int httpd_send_chunk_begin(int conn, int size) { int err; char buf[CHUNK_SIZE_DIGITS]; int i; int digit; int begin = 1; for (i = CHUNK_SIZE_DIGITS - 1; i >= 0; i--) { digit = size & 0xf; if (!begin && !size) { i++; break; } buf[i] = (digit > 9) ? digit - 0xA + 'a' : digit + '0'; size = size >> 4; begin = 0; } err = httpd_send(conn, &buf[i], CHUNK_SIZE_DIGITS - i); if (err != WM_SUCCESS) { return err; } err = httpd_send_crlf(conn); return err; }
/* Helper function to send an error. */ int httpd_send_error(int conn, int http_error) { int err = 0; switch (http_error) { case HTTP_404: err = httpd_send(conn, http_header_404, strlen(http_header_404)); break; case HTTP_500: err = httpd_send(conn, http_header_500, strlen(http_header_500)); break; case HTTP_505: err = httpd_send(conn, http_header_505, strlen(http_header_505)); break; } if (err != WM_SUCCESS) { return err; } err = httpd_send(conn, http_header_type_chunked, strlen(http_header_type_chunked)); if (err != WM_SUCCESS) { return err; } err = httpd_send(conn, http_content_type_plain, sizeof(http_content_type_plain) - 1); if (err != WM_SUCCESS) { return err; } err = httpd_send_crlf(conn); if (err != WM_SUCCESS) { return err; } err = httpd_send_chunk(conn, httpd_error, strlen(httpd_error)); if (err != WM_SUCCESS) { return err; } return httpd_send_last_chunk(conn); }
/* Send the last chunk which is simply an ascii "0\r\n\r\n" */ int httpd_send_last_chunk(int conn) { int err; err = httpd_send(conn, http_last_chunk, sizeof(http_last_chunk) - 1); if (err != WM_SUCCESS) { httpd_e("Send last chunk failed"); } return err; }
static int httpd_send_file(struct fs *fs, int conn, const sys_file_t *sys_file_p) { char data[SND_BUF_LEN]; int len; int total = 0; int err = WM_SUCCESS; /* Chunk begin */ err = httpd_send_chunk_begin(conn, htsys_get_file_size(fs, sys_file_p)); if (err != WM_SUCCESS) return err; /* Send the file */ while (TRUE) { len = htsys_read(fs, sys_file_p, (unsigned char *)data, SND_BUF_LEN); if (len <= 0) { if (len < 0) httpd_d("read failed\r\n"); break; } err = httpd_send(conn, data, len); if (err != WM_SUCCESS) { httpd_d("Failed to send file (sent %d bytes)\r\n", total); break; } total += len; } htsys_close(fs, sys_file_p); if (err != WM_SUCCESS) { return err; } /* Chunk end */ err = httpd_send_crlf(conn); return err; }
int httpd_send_hdr_from_code(int sock, int stat_code, enum http_content_type content_type) { const char *str; unsigned int str_len; /* * Set the HTTP Response Status 200 OK, 404 NOT FOUND etc. * Also set the Transfer-Encoding to chunked. */ switch (stat_code) { case -WM_E_HTTPD_HANDLER_404: str = http_header_404; str_len = strlen(http_header_404); break; case -WM_E_HTTPD_HANDLER_400: str = http_header_400; str_len = strlen(http_header_400); break; case -WM_E_HTTPD_HANDLER_500: str = http_header_500; str_len = strlen(http_header_500); break; default: /* The handler doesn't want an HTTP error code, but would return * 200 OK with an error in the response */ str = http_header_200; str_len = strlen(http_header_200); break; } if (httpd_send(sock, str, str_len) != WM_SUCCESS) { return -WM_FAIL; } /* Send the Content-Type */ switch (content_type) { case HTTP_CONTENT_JSON: str = http_content_type_json_nocache; str_len = sizeof(http_content_type_json_nocache) - 1; break; case HTTP_CONTENT_XML: str = http_content_type_xml_nocache; str_len = sizeof(http_content_type_xml_nocache) - 1; break; case HTTP_CONTENT_HTML: str = http_content_type_html; str_len = sizeof(http_content_type_html) - 1; break; case HTTP_CONTENT_JPEG: str = http_content_type_jpg; str_len = sizeof(http_content_type_jpg) - 1; break; default: str = http_content_type_plain; str_len = sizeof(http_content_type_plain) - 1; break; } if (httpd_send(sock, str, str_len) != WM_SUCCESS) { return -WM_FAIL; } return WM_SUCCESS; }
int http_get(struct httpd * httpd, struct httpctl * ctl) { int (* cgi)(struct tcp_pcb * tp); char buf[128]; // int content_type; // int content_len; // char * opt; char * ext; struct stat sb; int type; int hash; int size; int ret; int fd; int n; strcpy(buf, httpd->root); strcat(buf, ctl->uri); // for (opt = buf; (*opt); opt++) { // if (*opt == '?') { // *opt++ = '\0'; // break; // } // } DBG(DBG_INFO, "path=%s", buf); if ((ret = stat(buf, &sb)) < 0) { DBG(DBG_ERROR, "404 File Not Found"); httpd_404(ctl->tp); return ret; } if (S_ISDIR(sb.st_mode)) { DBG(DBG_INFO, "is a directory"); strcat(buf, "/"); strcat(buf, httpd_page_default); if ((ret = stat(buf, &sb)) < 0) { strcpy(buf, httpd->root); strcat(buf, ctl->uri); return httpd_dirlist(httpd, ctl); } } if (!S_ISREG(sb.st_mode)) { DBG(DBG_ERROR, "403 Forbidden"); httpd_403(ctl->tp); return -1; } if ((fd = open(buf, O_RDONLY)) < 0) { DBG(DBG_ERROR, "404 File Not Found"); httpd_404(ctl->tp); return -1; } ret = 0; if ((ext = strrchr(buf, '.')) != NULL) { DBG(DBG_INFO, "extension=%s", ext); /* skip the '.' */ ext++; hash = mk_ext_hash(ext); switch (hash) { case EXT_CGI: DBG(DBG_INFO, "cgi"); goto dynamic_cgi; case EXT_TXT: DBG(DBG_INFO, "text"); type = text_plain; break; case EXT_JPEG: case EXT_JPG: DBG(DBG_INFO, "jpeg"); type = image_jpeg; break; case EXT_ICO: DBG(DBG_INFO, "ico"); case EXT_GIF: DBG(DBG_INFO, "gif"); type = image_gif; break; case EXT_PNG: DBG(DBG_INFO, "png"); type = image_png; break; case EXT_JS: DBG(DBG_INFO, "js"); type = application_x_javascript; break; case EXT_HTML: case EXT_HTM: DBG(DBG_INFO, "html"); default: type = text_html; break; } httpd_200(ctl->tp, type); while ((n = read(fd, buf, 128)) > 0) { if (tcp_send(ctl->tp, buf, n, 0) <= 0) { DBG(DBG_ERROR, "tcp_send()"); ret = -1; break; } } } else { dynamic_cgi: size = lseek(fd, 0, SEEK_END); DBG(DBG_TRACE, "size=%d", size); cgi = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); DBG(DBG_TRACE, "cgi=%p", cgi); ret = cgi(ctl->tp); } close(fd); #if 0 DBG(DBG_INFO, "file uid=%d", info.fi_uid); if (info.fi_uid < __httpd->uid) { unsigned int uid; DBG(DBG_INFO, "info.fi_uid=%d < httpd->uid=%d, auth required", info.fi_uid, __httpd->uid); uid = httpd_auth(__http->httpd, __http->usr, __http->pwd); if (info.fi_uid < uid) { DBG(DBG_ERROR, "401 Unauthorized, uid=%d", uid); httpd_401_auth(__tp); return -1; } } content_type = __http->ctype; content_len = __http->ctlen; if (info.fi_mime != _code_) { /* detach the PCB */ tcp_attach(__tp, NULL, __httpd); /* release the control structure */ httpd_free(__httpd, __http); httpd_send(__tp, info.fi_mime, (char *)info.fi_data, info.fi_size); tcp_close(__tp); return 0; } /* dynamic cgi */ DBG(DBG_INFO, "dynamic page"); cgi_call = (httpd_cgi_t)info.fi_data; /* reuse the allocated buffer */ cgi = (struct cgistate *)__http; /* XXX: */ cgi->httpd = __httpd; cgi->callback = NULL; /* attach the PCB to the CGI handler */ tcp_attach(__tp, (tcp_callback_t)httpd_cgi_handler, cgi); if (cgi_call(__tp, opt, content_type, content_len) < 0) { /* close the tcp pcb */ tcp_close(__tp); } else { /* if the CGI is still detached, close-it */ if (cgi->callback == NULL) tcp_close(__tp); } #endif return ret; }
_mqx_int httpd_sendstr(_mqx_int s, char *str) { return httpd_send(s, str, strlen(str)); }
void httpd_sendfile(HTTPD_STRUCT *server, HTTPD_SESSION_STRUCT *session) { char *ext; int expand = 0; int len; char buf[HTTPDCFG_MAX_BYTES_TO_SEND + 1]; HTTPD_ASSERT(server && session); HTTPD_DEBUG(3, "httpd_sendfile(%p) %s\n", session, session->request.path); ext = strrchr(session->request.path, 46); if (ext) { if (0 == strcasecmp(ext, ".htm") || 0 == strcasecmp(ext, ".html")) { session->response.contenttype = CONTENT_TYPE_HTML; expand = 1; } else if (0 == strcasecmp(ext, ".gif")) session->response.contenttype = CONTENT_TYPE_GIF; else if (0 == strcasecmp(ext, ".jpg")) session->response.contenttype = CONTENT_TYPE_JPG; else if (0 == strcasecmp(ext, ".png")) session->response.contenttype = CONTENT_TYPE_PNG; else if (0 == strcasecmp(ext, ".css")) session->response.contenttype = CONTENT_TYPE_CSS; else if (0 == strcasecmp(ext, ".js")) session->response.contenttype = CONTENT_TYPE_JS; else session->response.contenttype = CONTENT_TYPE_OCTETSTREAM; } if (expand) { //if there will be any expansion there's no way how to calculate correct length //zero length prevents sending Content-Length header field httpd_sendhdr(session, 0, 0); } else { httpd_sendhdr(session, session->response.file->SIZE, 0); } if (expand) { session->response.data = buf; len = read(session->response.file, session->response.data, HTTPDCFG_MAX_BYTES_TO_SEND); if (len > 0) { buf[len] = 0; len = httpd_sendextstr(server, session, session->response.data); if (!len) { session->state = HTTPD_SES_END_REQ; } else { session->response.len += len; fseek(session->response.file, session->response.len, SEEK_SET); } } else session->state = HTTPD_SES_END_REQ; } else { session->response.data = buf; fseek(session->response.file, session->response.len, SEEK_SET); len = read(session->response.file, session->response.data, HTTPDCFG_MAX_BYTES_TO_SEND); HTTPD_DEBUG(4, "httpd_sendfile READ END %d\n", len); if (len > 0) { buf[len] = 0; len = httpd_send(session->sock, session->response.data, len); if (len < 0) { if (errno != EAGAIN) session->state = HTTPD_SES_END_REQ; } else { session->response.len += len; } } else session->state = HTTPD_SES_END_REQ; } HTTPD_DEBUG(4, "httpd_sendfile END %s \n", session->request.path); }
/** Send extended string to socket. * \param s < socket * \param str < pointer to string * \return length of sent data */ static _mqx_int httpd_sendextstr(HTTPD_STRUCT *server, HTTPD_SESSION_STRUCT *session, char *str) { char *src; int len, res; char fname[HTTPDCFG_MAX_SCRIPT_LN + 1]; HTTPD_ASSERT(server && session && str); fname[0] = 0; if (!session->response.data) { session->response.data = str; } src = session->response.data; if (session->response.script_token) { // script token found len = (int)strcspn(src, " ;%<>\r\n\t"); if (len > 1 && len < HTTPDCFG_MAX_SCRIPT_LN) { strncpy(fname, src, (unsigned long)len); fname[len] = 0; // call fn HTTPD_DEBUG(2, "script ln: %s\r\n", fname); httpd_call_fn(server, session, fname); } if (src[len] == '%' && src[len + 1] == '>') { session->response.script_token = 0; len += 1; } len++; session->response.data = src + len; } else { for (len = 0; *src && len < HTTPDCFG_MAX_BYTES_TO_SEND; src++, len++) { if (*src == '<' && *(src + 1) == '%') { session->response.script_token = 1; src += 2; break; } } res = httpd_send(session->sock, session->response.data, len); if (res < 0) { session->response.script_token = 0; res = errno; if (res != EAGAIN) len = 0; } else { if (len == res) { session->response.data = src; } else { session->response.script_token = 0; session->response.data += res; } } } return len; }
int httpd_handle_file(httpd_request_t *req_p, struct fs *fs) { const char *anchor = "/"; char tmp[HTTPD_MAX_URI_LENGTH+1]; const char *encoding = NULL; char *msg_in, *ptr, *type = NULL; int err, msg_in_len = HTTPD_MAX_MESSAGE - 1, conn = req_p->sock; int ret; msg_in = os_mem_alloc(HTTPD_MAX_MESSAGE + 2); if (!msg_in) { httpd_e("Failed to allocate memory for file handling"); /* Check what needs to be returned */ return -WM_FAIL; } memset(msg_in, 0, HTTPD_MAX_MESSAGE + 2); SYS_FILE_DECL; if (!fs) { /* The filesystem wasn't mounted properly */ httpd_send_hdr_from_str(conn, http_header_404, CONTENT_TYPE_PLAIN, encoding, NO_CACHE_HEADERS, UNUSED_PARAM); httpd_send_default_headers(conn, req_p->wsgi->hdr_fields); httpd_send_crlf(conn); httpd_send(conn, FILE_NOT_FOUND, sizeof(FILE_NOT_FOUND)); ret = WM_SUCCESS; goto out; } struct ftfs_super *f_super = fs_to_ftfs_sb(fs); /* Ensure that the anchor is the first part of the filename */ ptr = strstr(req_p->filename, anchor); if (ptr == NULL || ptr != req_p->filename) { httpd_d("No anchor in filename\r\n"); ret = httpd_send_error(conn, HTTP_500); goto out; } /* Zap the anchor from the filename */ ptr = req_p->filename + strlen(anchor); err = 0; /* anchors are only across directory boundaries */ if (*ptr != '/') req_p->filename[err++] = '/'; while (*ptr && (*ptr != '?')) { req_p->filename[err] = *ptr; ptr++; err++; } req_p->filename[err] = '\0'; /* "/" implies a request for index.html */ if (strncmp(req_p->filename, "/", 2) == 0) { strncpy(req_p->filename, http_index_html, sizeof(http_index_html)); } /* Find if .gz version exists for file, if it is then serve that */ type = strrchr(req_p->filename, ISO_period); if (type) { strncpy(tmp, req_p->filename, sizeof(tmp)); strncat(tmp, ".gz", 3); httpd_d("Look for gz file if it exists: %s\r\n", tmp); if (htsys_file_open(fs, tmp, sys_filep) == WM_SUCCESS) { /* Gzipped version exists, serve that */ httpd_d("Serve gzipped file\r\n"); strncpy(req_p->filename, tmp, HTTPD_MAX_URI_LENGTH + 1); encoding = ".gz"; htsys_close(fs, sys_filep); } } ret = httpd_parse_hdr_tags(req_p, conn, msg_in, msg_in_len); if (ret < 0) { httpd_d("Parsing headers failed \r\n"); ret = httpd_send_error(conn, HTTP_500); goto out; } /* It is not a WSGI, check to see if the file exists */ if (htsys_file_open(fs, req_p->filename, sys_filep) == -WM_FAIL) { httpd_w("file not found: %s\r\n", req_p->filename); ret = httpd_send_hdr_from_str(conn, http_header_404, type, encoding, NO_CACHE_HEADERS, UNUSED_PARAM); httpd_send_default_headers(conn, req_p->wsgi->hdr_fields); httpd_send_crlf(conn); if (ret != WM_SUCCESS) goto out; ret = htsys_file_open(fs, http_404_html, sys_filep); if (ret == WM_SUCCESS) { ret = httpd_send_file(fs, conn, sys_filep); goto out; } else httpd_w("No local 404 file. Sending empty 404" " response.\r\n"); } else { /* Ok, the file exists, is it a script html or just html */ g_wm_stats.wm_hd_file++; if (req_p->if_none_match && (f_super->fs_crc32 == req_p->etag_val)) { /* We do not need the file handle now */ htsys_close(fs, sys_filep); /* Send Not Modified header */ /* Send header prologue */ ret = httpd_send(conn, http_header_304_prologue, strlen(http_header_304_prologue)); if (ret != WM_SUCCESS) goto out; httpd_send_header(conn, "Server", "Marvell-WM"); httpd_send_header(conn, "Connection", "Close"); /* Send ETag */ int len; const char *h = httpd_get_etag_hdr(req_p->etag_val, &len); ret = httpd_send(conn, h, len); if (ret != WM_SUCCESS) goto out; /* Close the header */ ret = httpd_send_crlf(conn); goto out; } else { ret = httpd_send_hdr_from_str(conn, http_header_200, type, encoding, SEND_CACHE_HEADERS, f_super->fs_crc32); httpd_send_default_headers(conn, req_p->wsgi->hdr_fields); httpd_send_crlf(conn); if (ret != WM_SUCCESS) goto out; ptr = strchr(req_p->filename, ISO_period); if (ptr != NULL && strncmp(ptr, http_shtml, sizeof(http_shtml) - 1) == 0) { httpd_d("Handling script: %s", req_p->filename); ret = handle_script(fs, req_p, conn, sys_filep, msg_in); htsys_close(fs, sys_filep); if (ret != WM_SUCCESS) { httpd_d("Script failed\r\n"); goto out; } } else { ret = httpd_send_file(fs, conn, sys_filep); if (ret != WM_SUCCESS) goto out; } } } ret = httpd_send_last_chunk(conn); out: os_mem_free(msg_in); return ret; }
/* Send the required HTTP headers on the connection conn */ static int httpd_send_hdr_from_str(int conn, const char *statushdr, const char *file_type, const char *encoding, bool send_cache_headers, unsigned etag_val) { int err; /* Send the HTTP status header, 200/404, etc.*/ err = httpd_send(conn, statushdr, strlen(statushdr)); if (err != WM_SUCCESS) { return err; } /* Set enconding to gz if so */ if (strncmp(encoding, http_gz, sizeof(http_gz) - 1) == 0) { err = httpd_send(conn, http_content_encoding_gz, sizeof(http_content_encoding_gz) - 1); if (err != WM_SUCCESS) return err; } if (send_cache_headers && strncmp(http_shtml, file_type, sizeof(http_shtml) - 1)) { err = httpd_send(conn, http_cache_control, sizeof(http_cache_control) - 1); if (err != WM_SUCCESS) return err; int len; const char *etag_hdr = httpd_get_etag_hdr(etag_val, &len); err = httpd_send(conn, etag_hdr, len); if (err != WM_SUCCESS) return err; } if (file_type == NULL) { err = httpd_send(conn, http_content_type_binary, sizeof(http_content_type_binary) - 1); } else if (strncmp(http_manifest, file_type, sizeof(http_manifest) - 1) == 0) { err = httpd_send(conn, http_content_type_text_cache_manifest, sizeof(http_content_type_text_cache_manifest) - 1); } else if (strncmp(http_html, file_type, sizeof(http_html) - 1) == 0) { err = httpd_send(conn, http_content_type_html, sizeof(http_content_type_html) - 1); } else if (strncmp(http_shtml, file_type, sizeof(http_shtml) - 1) == 0) { err = httpd_send(conn, http_content_type_html_nocache, sizeof(http_content_type_html_nocache) - 1); } else if (strncmp(http_css, file_type, sizeof(http_css) - 1) == 0) { err = httpd_send(conn, http_content_type_css, sizeof(http_content_type_css) - 1); } else if (strncmp(http_js, file_type, sizeof(http_js) - 1) == 0) { err = httpd_send(conn, http_content_type_js, sizeof(http_content_type_js) - 1); } else if (strncmp(http_png, file_type, sizeof(http_png) - 1) == 0) { err = httpd_send(conn, http_content_type_png, sizeof(http_content_type_png) - 1); } else if (strncmp(http_gif, file_type, sizeof(http_gif) - 1) == 0) { err = httpd_send(conn, http_content_type_gif, sizeof(http_content_type_gif) - 1); } else if (strncmp(http_jpg, file_type, sizeof(http_jpg) - 1) == 0) { err = httpd_send(conn, http_content_type_jpg, sizeof(http_content_type_jpg) - 1); } else { err = httpd_send(conn, http_content_type_plain, sizeof(http_content_type_plain) - 1); } return err; }
/* If a script file (shtml), script_file_p is found, send that file to * the client over the socket, conn. Process any SSI directives within * the file. */ static int handle_script(struct fs *fs, httpd_request_t *req, int conn, sys_file_t *script_file_p, char *data_p) { char *cmd, *args; int len, err; int script_cmd; httpd_ssifunction func; SYS_FILE_DECL; err = WM_SUCCESS; /* proccess each line of the script */ while ((len = htsys_getln(fs, script_file_p, data_p, HTTPD_MAX_MESSAGE + 1)) != 0) { if (len < 0) { httpd_d("getln failed\r\n"); err = -WM_FAIL; break; } /* Check if we should start executing a script. */ script_cmd = httpd_is_script_directive(data_p, len, &cmd, &args); if (script_cmd == SSI_INCLUDE_FILE) { /* Include another file and send to client */ if (cmd == NULL) continue; httpd_d("Opening %s from script", cmd); err = htsys_file_open(fs, cmd, sys_filep); if (err != WM_SUCCESS) { httpd_d("open failed\r\n"); break; } httpd_d("sending file %s (%d bytes).\r\n", cmd, htsys_get_file_size(fs, sys_filep)); err = httpd_send_file(fs, conn, sys_filep); if (err != WM_SUCCESS) { break; } } else if (script_cmd == SSI_INCLUDE_VIRTUAL) { /* find the function and run it */ /* it should always at least return a nullfunction */ if (cmd == NULL) continue; httpd_d("Invoking SSI %s from script", cmd); func = httpd_ssi(cmd); /* Pass args in their own buffer so we can use data_p as * scratch */ if (args == NULL) { err = func(req, NULL, conn, data_p); } else { strncpy(script_args, args, HTTPD_MAX_SSI_ARGS); script_args[HTTPD_MAX_SSI_ARGS] = 0; err = func(req, script_args, conn, data_p); } } else { /* send embedded html to client */ err = httpd_send_chunk_begin(conn, len); if (err != WM_SUCCESS) break; err = httpd_send(conn, data_p, len); if (err != WM_SUCCESS) break; err = httpd_send_crlf(conn); if (err != WM_SUCCESS) break; } } return err; }
// HTTP event handler void tcp_handle_event(chanend tcp_svr, xtcp_connection_t *conn) { // We have received an event from the TCP stack, so respond // appropriately // Ignore events that are not directly relevant to http switch (conn->event) { case XTCP_IFUP: { xtcp_ipconfig_t ipconfig; xtcp_get_ipconfig(tcp_svr, &ipconfig); #if IPV6 unsigned short a; unsigned int i; int f; xtcp_ipaddr_t *addr = &ipconfig.ipaddr; printstr("IPV6 Address = ["); for(i = 0, f = 0; i < sizeof(xtcp_ipaddr_t); i += 2) { a = (addr->u8[i] << 8) + addr->u8[i + 1]; if(a == 0 && f >= 0) { if(f++ == 0) { printstr("::"); } } else { if(f > 0) { f = -1; } else if(i > 0) { printstr(":"); } printhex(a); } } printstrln("]"); #else printstr("IP Address: "); printint(ipconfig.ipaddr[0]);printstr("."); printint(ipconfig.ipaddr[1]);printstr("."); printint(ipconfig.ipaddr[2]);printstr("."); printint(ipconfig.ipaddr[3]);printstr("\n"); #endif } return; case XTCP_IFDOWN: case XTCP_ALREADY_HANDLED: return; default: break; } // Check if the connection is a http connection if (conn->local_port == 80) { switch (conn->event) { case XTCP_NEW_CONNECTION: httpd_init_state(tcp_svr, conn); break; case XTCP_RECV_DATA: httpd_recv(tcp_svr, conn); break; case XTCP_SENT_DATA: case XTCP_REQUEST_DATA: case XTCP_RESEND_DATA: httpd_send(tcp_svr, conn); break; case XTCP_TIMED_OUT: case XTCP_ABORTED: case XTCP_CLOSED: httpd_free_state(conn); break; default: // Ignore anything else break; } conn->event = XTCP_ALREADY_HANDLED; } //// return; }