/*
** 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);
}
Example #6
0
/*
** 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;
        }    
    }
}