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

Dependencies:   mbed EthernetInterface HTTPClient mbed-rtos

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers HTTPPoster.cpp Source File

HTTPPoster.cpp

00001 /* HTTPPoster.cpp */
00002 
00003 //Debug is disabled by default
00004 #if 1
00005 //Enable debug
00006 #include <cstdio>
00007 #define DBG(x, ...) std::printf("[HTTPPoster : DBG]"x"\r\n", ##__VA_ARGS__); 
00008 //#define DBG(x, ...) 
00009 #define WARN(x, ...) std::printf("[HTTPPoster : WARN]"x"\r\n", ##__VA_ARGS__); 
00010 #define ERR(x, ...) std::printf("[HTTPPoster : ERR]"x"\r\n", ##__VA_ARGS__); 
00011 
00012 #else
00013 //Disable debug
00014 #define DBG(x, ...) 
00015 #define WARN(x, ...)
00016 #define ERR(x, ...) 
00017 
00018 #endif
00019 
00020 #include "HTTPPoster.h"
00021 
00022 #define OK 0
00023 
00024 ///HTTP Client data container for form(multipart/form-data)
00025 HTTPPoster::HTTPPoster()
00026 {
00027     m_cur = 0;
00028     m_seq = 0;
00029     m_send_len = 0;
00030     m_fp = NULL;
00031     m_post_data.clear();
00032     m_buf.clear();
00033     m_boundary = "----HTTPPoster123";
00034     m_ContentType = "multipart/form-data; boundary="; 
00035     m_ContentType += m_boundary;
00036 }
00037 
00038 HTTPPoster::~HTTPPoster()
00039 {
00040     if (m_fp) {
00041         fclose(m_fp);
00042         m_fp = NULL;
00043     }
00044 }
00045 
00046 bool HTTPPoster::addFile(const char* name, const char* path)
00047 {
00048     struct stpost data;
00049 
00050     m_fp = fopen(path, "rb");
00051     if (m_fp == NULL) {
00052         return false;
00053     }
00054     fseek(m_fp, 0, SEEK_END);
00055     data.length = ftell(m_fp);
00056     fclose(m_fp);
00057 
00058     string head = "Content-Disposition: form-data; name=\"";
00059     head += name;
00060     head += "\"; filename=\"";
00061     head += path; 
00062     head += "\"";
00063 
00064     data.head = head;
00065     data.value = path;
00066     data.file = true;
00067     m_post_data.push_back(data);
00068     return true;
00069 }
00070 
00071 bool HTTPPoster::add(const char* name, const char* value)
00072 {
00073     struct stpost data;
00074 
00075     string head = "Content-Disposition: form-data; name=\"";
00076     head += name;
00077     head += "\"";
00078 
00079     data.head = head;
00080     data.value = value;
00081     data.length = strlen(value);    
00082     data.file = false;
00083     m_post_data.push_back(data);
00084     return true;
00085 }
00086 
00087 /*virtual*/ int HTTPPoster::read(char* buf, size_t len, size_t* pReadLen)
00088 {
00089     int c;
00090     switch(m_seq) {
00091         case 0:
00092             if (m_cur >= m_post_data.size()) {
00093                 m_buf += "--";
00094                 m_buf += m_boundary;
00095                 m_buf += "--\r\n";
00096                 m_seq = 4; // done
00097             } else {
00098                 m_buf += "--";
00099                 m_buf += m_boundary;
00100                 m_buf += "\r\n";
00101                 m_seq++;
00102             }
00103             break;
00104         case 1:
00105             m_buf += m_post_data[m_cur].head;
00106             m_buf += "\r\n\r\n";
00107             if (m_post_data[m_cur].file) {
00108                 m_fp = fopen(m_post_data[m_cur].value.c_str(), "rb");
00109             }
00110             m_pos = 0;
00111             m_seq++;
00112             break;
00113         case 2:
00114             for(int i = 0; i < len; i++) {
00115                 if (m_buf.size() >= len) {
00116                     break;
00117                 }
00118                 if (m_pos >= m_post_data[m_cur].length) {
00119                     m_seq++;
00120                     break;
00121                 }
00122                 if (m_post_data[m_cur].file) {
00123                     c = fgetc(m_fp);
00124                 } else {
00125                     c = m_post_data[m_cur].value[m_pos];
00126                 }
00127                 m_buf += (char)c;
00128                 m_pos++;
00129             }
00130             break;            
00131         case 3:
00132             m_buf += "\r\n";
00133             if (m_fp) {
00134                 fclose(m_fp);
00135                 m_fp = NULL;
00136             }
00137             m_cur++;
00138             m_seq = 0;
00139             break;
00140         default: // done
00141             break;
00142     }
00143     int len2 = m_buf.size();
00144     if (len2 > len) {
00145         len2 = len;
00146     }
00147     memcpy(buf, m_buf.data(), len2);
00148     m_buf.erase(0, len2);
00149     m_send_len += len2;
00150     DBG("m_len=%d m_send_len=%d len=%d len2=%d", m_len, m_send_len, len, len2);
00151     *pReadLen = len2;
00152     return OK;
00153 }
00154 
00155 /*virtual*/ int HTTPPoster::getDataType(char* type, size_t maxTypeLen) //Internet media type for Content-Type header
00156 {
00157     if (m_ContentType.length() >= maxTypeLen) {
00158         WARN("maxTypeLen=%d", maxTypeLen);
00159         WARN("m_ContentType.length()=%d", m_ContentType.length());
00160         return !OK;
00161     }
00162     strcpy(type, m_ContentType.c_str());
00163     return OK;
00164 }
00165 
00166 /*virtual*/ bool HTTPPoster::getIsChunked() //For Transfer-Encoding header
00167 {
00168     return false; ////Data is computed one key/value pair at a time
00169 }
00170 
00171 /*virtual*/ size_t HTTPPoster::getDataLen() //For Content-Length header
00172 {
00173     m_len = 0;
00174     for(int i = 0; i < m_post_data.size(); i++) {
00175         m_len += 2 + strlen(m_boundary) + 2;      // "--" boundary CRLF
00176         m_len += m_post_data[i].head.size() + 2; // Content-Disposition: ... CRLF
00177         m_len += 2;                               // CRLF  
00178         m_len += m_post_data[i].length;           // value / file body
00179         m_len += 2;                               // CRLF
00180     }
00181     m_len += 2 + strlen(m_boundary) + 2 + 2;   // "--" boundary "--" CRLF
00182     return m_len;
00183 }