HTTP Client data container for form(multipart/form-data)

Dependencies:   mbed EthernetInterface HTTPClient mbed-rtos

HTTPPoster.cpp

Committer:
va009039
Date:
2012-08-28
Revision:
1:77c616a1ab54
Parent:
0:fcd577a3925b

File content as of revision 1:77c616a1ab54:

/* HTTPPoster.cpp */

//Debug is disabled by default
#if 1
//Enable debug
#include <cstdio>
#define DBG(x, ...) std::printf("[HTTPPoster : DBG]"x"\r\n", ##__VA_ARGS__); 
//#define DBG(x, ...) 
#define WARN(x, ...) std::printf("[HTTPPoster : WARN]"x"\r\n", ##__VA_ARGS__); 
#define ERR(x, ...) std::printf("[HTTPPoster : ERR]"x"\r\n", ##__VA_ARGS__); 

#else
//Disable debug
#define DBG(x, ...) 
#define WARN(x, ...)
#define ERR(x, ...) 

#endif

#include "HTTPPoster.h"

#define OK 0

///HTTP Client data container for form(multipart/form-data)
HTTPPoster::HTTPPoster()
{
    m_cur = 0;
    m_seq = 0;
    m_send_len = 0;
    m_fp = NULL;
    m_post_data.clear();
    m_buf.clear();
    m_boundary = "----HTTPPoster123";
    m_ContentType = "multipart/form-data; boundary="; 
    m_ContentType += m_boundary;
}

HTTPPoster::~HTTPPoster()
{
    if (m_fp) {
        fclose(m_fp);
        m_fp = NULL;
    }
}

bool HTTPPoster::addFile(const char* name, const char* path)
{
    struct stpost data;

    m_fp = fopen(path, "rb");
    if (m_fp == NULL) {
        return false;
    }
    fseek(m_fp, 0, SEEK_END);
    data.length = ftell(m_fp);
    fclose(m_fp);

    string head = "Content-Disposition: form-data; name=\"";
    head += name;
    head += "\"; filename=\"";
    head += path; 
    head += "\"";

    data.head = head;
    data.value = path;
    data.file = true;
    m_post_data.push_back(data);
    return true;
}

bool HTTPPoster::add(const char* name, const char* value)
{
    struct stpost data;

    string head = "Content-Disposition: form-data; name=\"";
    head += name;
    head += "\"";

    data.head = head;
    data.value = value;
    data.length = strlen(value);    
    data.file = false;
    m_post_data.push_back(data);
    return true;
}

/*virtual*/ int HTTPPoster::read(char* buf, size_t len, size_t* pReadLen)
{
    int c;
    switch(m_seq) {
        case 0:
            if (m_cur >= m_post_data.size()) {
                m_buf += "--";
                m_buf += m_boundary;
                m_buf += "--\r\n";
                m_seq = 4; // done
            } else {
                m_buf += "--";
                m_buf += m_boundary;
                m_buf += "\r\n";
                m_seq++;
            }
            break;
        case 1:
            m_buf += m_post_data[m_cur].head;
            m_buf += "\r\n\r\n";
            if (m_post_data[m_cur].file) {
                m_fp = fopen(m_post_data[m_cur].value.c_str(), "rb");
            }
            m_pos = 0;
            m_seq++;
            break;
        case 2:
            for(int i = 0; i < len; i++) {
                if (m_buf.size() >= len) {
                    break;
                }
                if (m_pos >= m_post_data[m_cur].length) {
                    m_seq++;
                    break;
                }
                if (m_post_data[m_cur].file) {
                    c = fgetc(m_fp);
                } else {
                    c = m_post_data[m_cur].value[m_pos];
                }
                m_buf += (char)c;
                m_pos++;
            }
            break;            
        case 3:
            m_buf += "\r\n";
            if (m_fp) {
                fclose(m_fp);
                m_fp = NULL;
            }
            m_cur++;
            m_seq = 0;
            break;
        default: // done
            break;
    }
    int len2 = m_buf.size();
    if (len2 > len) {
        len2 = len;
    }
    memcpy(buf, m_buf.data(), len2);
    m_buf.erase(0, len2);
    m_send_len += len2;
    DBG("m_len=%d m_send_len=%d len=%d len2=%d", m_len, m_send_len, len, len2);
    *pReadLen = len2;
    return OK;
}

/*virtual*/ int HTTPPoster::getDataType(char* type, size_t maxTypeLen) //Internet media type for Content-Type header
{
    if (m_ContentType.length() >= maxTypeLen) {
        WARN("maxTypeLen=%d", maxTypeLen);
        WARN("m_ContentType.length()=%d", m_ContentType.length());
        return !OK;
    }
    strcpy(type, m_ContentType.c_str());
    return OK;
}

/*virtual*/ bool HTTPPoster::getIsChunked() //For Transfer-Encoding header
{
    return false; ////Data is computed one key/value pair at a time
}

/*virtual*/ size_t HTTPPoster::getDataLen() //For Content-Length header
{
    m_len = 0;
    for(int i = 0; i < m_post_data.size(); i++) {
        m_len += 2 + strlen(m_boundary) + 2;      // "--" boundary CRLF
        m_len += m_post_data[i].head.size() + 2; // Content-Disposition: ... CRLF
        m_len += 2;                               // CRLF  
        m_len += m_post_data[i].length;           // value / file body
        m_len += 2;                               // CRLF
    }
    m_len += 2 + strlen(m_boundary) + 2 + 2;   // "--" boundary "--" CRLF
    return m_len;
}