/* ** Write data to buffer. If buffer is full during write flush it to client. ** ** IN: ** HTTPSRV_SESSION_STRUCT *session - session used for write. ** char* src - pointer to data to send. ** _mqx_int len - length of data in bytes. ** ** OUT: ** none ** ** Return Value: ** _mqx_int - number of bytes written. */ _mqx_int httpsrv_write(HTTPSRV_SESSION_STRUCT *session, char *src, _mqx_int len) { uint32_t space = HTTPSRV_SES_BUF_SIZE_PRV - session->buffer.offset; uint32_t retval = len; /* User buffer is bigger than session buffer - send user data directly */ if (len > HTTPSRV_SES_BUF_SIZE_PRV) { /* If there are some data already buffered send them to client first */ httpsrv_ses_flush(session); return(send(session->sock, src, len, 0)); } /* No space in buffer - make some */ if (space < len) { httpsrv_ses_flush(session); } /* Now we can save user data to buffer and eventually send them to client */ _mem_copy(src, session->buffer.data+session->buffer.offset, len); session->buffer.offset += len; if (session->buffer.offset >= HTTPSRV_SES_BUF_SIZE_PRV) { httpsrv_ses_flush(session); } return(retval); }
/* ** Send file to client ** ** IN: ** HTTPSRV_SESSION_STRUCT* session - session used for transmission ** HTTPSRV_STRUCT* server - server structure ** ** OUT: ** none ** ** Return Value: ** none */ void httpsrv_sendfile(HTTPSRV_STRUCT *server, HTTPSRV_SESSION_STRUCT *session) { char *ext; int length; char *buffer; buffer = session->buffer.data; ext = strrchr(session->request.path, '.'); httpsrv_process_file_type(ext, session); /* Check if file has server side includes */ if ((0 == strcasecmp(ext, ".shtml")) || (0 == strcasecmp(ext, ".shtm"))) { /* * Disable keep-alive for this session otherwise we would have to * wait for session timeout. */ session->keep_alive = 0; httpsrv_sendhdr(session, 0, 1); #if MQX_USE_IO_OLD fseek(session->response.file, session->response.len, IO_SEEK_SET); #else fseek(session->response.file, session->response.len, SEEK_SET); #endif length = fread(buffer+session->buffer.offset, 1, HTTPSRV_SES_BUF_SIZE_PRV-session->buffer.offset, session->response.file); if (length > 0) { uint32_t offset; offset = httpsrv_sendextstr(server, session, length); session->response.len += session->buffer.offset; httpsrv_ses_flush(session); session->response.len += offset; } } else { #if MQX_USE_IO_OLD httpsrv_sendhdr(session, session->response.file->SIZE, 1); fseek(session->response.file, session->response.len, IO_SEEK_SET); #else httpsrv_sendhdr(session, httpsrv_fsize(session->response.file), 1); fseek(session->response.file, session->response.len, SEEK_SET); #endif length = fread(buffer+session->buffer.offset, 1, HTTPSRV_SES_BUF_SIZE_PRV-session->buffer.offset, session->response.file); if (length > 0) { session->buffer.offset += length; httpsrv_ses_flush(session); session->response.len += length; } } if (length <= 0) { session->state = HTTPSRV_SES_END_REQ; } }
/* ** Send http header according to the session response structure. ** ** IN: ** HTTPSRV_SESSION_STRUCT* session - session used for transmission ** _mqx_int content_len - content length ** bool has_entity - flag indicating if HTTP entity is going to be send following header. ** ** OUT: ** none ** ** Return Value: ** none */ void httpsrv_sendhdr(HTTPSRV_SESSION_STRUCT *session, _mqx_int content_len, bool has_entity) { if (session->response.hdrsent) { return; } httpsrv_print(session, "%s %d %s\r\n", HTTPSRV_PROTOCOL_STRING, session->response.status_code, httpsrv_get_table_str((httpsrv_table_row*)reason_phrase, session->response.status_code)); httpsrv_print(session, "Server: %s\r\n", HTTPSRV_PRODUCT_STRING); /* Check authorization */ if (session->response.status_code == HTTPSRV_CODE_UNAUTHORIZED) { httpsrv_print(session, "WWW-Authenticate: Basic realm=\"%s\"\r\n", session->response.auth_realm->name); } httpsrv_print(session, "Connection: %s\r\n", session->keep_alive ? "Keep-Alive":"close"); /* If there will be entity body send content type */ if (has_entity) { httpsrv_print(session, "Content-Type: %s\r\n", httpsrv_get_table_str((httpsrv_table_row*)content_type, session->response.content_type)); } httpsrv_print(session, "Cache-Control: "); if (session->response.cacheable) { httpsrv_print(session, "max-age=%d\r\n", HTTPSRVCFG_CACHE_MAXAGE); } else { if (session->response.auth_realm != NULL) { httpsrv_print(session, "no-store\r\n"); } else { httpsrv_print(session, "no-cache\r\n"); } } /* Only non zero length cause sending Content-Length header field */ if (content_len > 0) { httpsrv_print(session, "Content-Length: %d\r\n", content_len); } /* End of header */ httpsrv_print(session, "\r\n"); /* Commented out to prevent problems with filesystem on KHCI USB */ //if ((content_len == 0) && (!has_entity)) { httpsrv_ses_flush(session); } session->response.hdrsent = 1; }
/* ** Send error page to client ** ** IN: ** HTTPSRV_SESSION_STRUCT* session - session used for transmission ** const char* title - title of error page ** const char* text - text displayed on error page ** ** OUT: ** none ** ** Return Value: ** none */ void httpsrv_send_err_page(HTTPSRV_SESSION_STRUCT *session, const char* title, const char* text) { uint32_t length; char* page; length = snprintf(NULL, 0, ERR_PAGE_FORMAT, title, text); length++; page = _mem_alloc(length*sizeof(char)); session->response.content_type = HTTPSRV_CONTENT_TYPE_HTML; if (page != NULL) { snprintf(page, length, ERR_PAGE_FORMAT, title, text); httpsrv_sendhdr(session, strlen(page), 1); httpsrv_write(session, page, strlen(page)); httpsrv_ses_flush(session); _mem_free(page); } else { httpsrv_sendhdr(session, 0, 0); } }
/* ** Print data to session ** ** IN: ** HTTPSRV_SESSION_STRUCT* session - session used for transmission ** char* format - format for snprintf function ** void ... - parameters to print ** ** OUT: ** none ** ** Return Value: ** none */ static void httpsrv_print(HTTPSRV_SESSION_STRUCT *session, char* format, ...) { va_list ap; uint32_t req_space = 0; char* buffer = session->buffer.data; int buffer_space = HTTPSRV_SES_BUF_SIZE_PRV - session->buffer.offset; va_start(ap, format); /* ** First we always test if there is enough space in buffer. If there is not, ** we flush it first and then write. */ req_space = vsnprintf(NULL, 0, format, ap); va_end(ap); va_start(ap, format); if (req_space > buffer_space) { httpsrv_ses_flush(session); buffer_space = HTTPSRV_SES_BUF_SIZE_PRV; } session->buffer.offset += vsnprintf(buffer+session->buffer.offset, buffer_space, format, ap); va_end(ap); }
/* ** Send file to client ** ** IN: ** HTTPSRV_SESSION_STRUCT* session - session used for transmission ** HTTPSRV_STRUCT* server - server structure ** ** OUT: ** none ** ** Return Value: ** none */ void httpsrv_sendfile(HTTPSRV_STRUCT *server, HTTPSRV_SESSION_STRUCT *session) { char *ext; int expand = 0; int len; char* buf = session->buffer.data; ext = strrchr(session->request.path, '.'); if (ext != NULL) { httpsrv_process_file_type(ext+1, session); } else { session->response.content_type = HTTPSRV_CONTENT_TYPE_OCTETSTREAM; } /* Check if file has server side includes */ if ((0 == strcasecmp(ext, ".shtml")) || (0 == strcasecmp(ext, ".shtm"))) { expand = 1; /* Disable keep-alive for this session otherwise we would have to wait for session timeout */ session->keep_alive = 0; /* If there will be any expansion there's no way how to calculate correct length ** zero length prevents sending Content-Length header field. */ httpsrv_sendhdr(session, 0, 1); } else { #if MQX_USE_IO_OLD httpsrv_sendhdr(session, session->response.file->SIZE, 1); #else httpsrv_sendhdr(session, httpsrv_fsize(session->response.file), 1); #endif } if (expand) { len = fread(buf+session->buffer.offset, 1, HTTPSRV_SES_BUF_SIZE_PRV-session->buffer.offset, session->response.file); if (len > 0) { len = httpsrv_sendextstr(server, session, buf, len); if (!len) { session->state = HTTPSRV_SES_END_REQ; } else { session->response.len += len; #if MQX_USE_IO_OLD fseek(session->response.file, session->response.len, IO_SEEK_SET); #else fseek(session->response.file, session->response.len, SEEK_SET); #endif } } else { session->state = HTTPSRV_SES_END_REQ; } } else { #if MQX_USE_IO_OLD fseek(session->response.file, session->response.len, IO_SEEK_SET); #else fseek(session->response.file, session->response.len, SEEK_SET); #endif len = fread(buf+session->buffer.offset, 1, HTTPSRV_SES_BUF_SIZE_PRV-session->buffer.offset, session->response.file); if (len > 0) { session->buffer.offset += len; httpsrv_ses_flush(session); session->response.len += len; } else { session->state = HTTPSRV_SES_END_REQ; } } }