From: <at...@us...> - 2007-08-22 17:46:36
|
Revision: 484 http://cadcdev.svn.sourceforge.net/cadcdev/?rev=484&view=rev Author: atani Date: 2007-08-22 10:46:32 -0700 (Wed, 22 Aug 2007) Log Message: ----------- updates to support POST requests Modified Paths: -------------- tiki/examples/net/httpclient/src/main.cpp tiki/include/Tiki/net/buffer.h tiki/include/Tiki/net/http/request.h tiki/include/Tiki/net/http/useragent.h tiki/src/net/http/request.cpp tiki/src/net/http/useragent.cpp Modified: tiki/examples/net/httpclient/src/main.cpp =================================================================== --- tiki/examples/net/httpclient/src/main.cpp 2007-08-22 00:39:13 UTC (rev 483) +++ tiki/examples/net/httpclient/src/main.cpp 2007-08-22 17:46:32 UTC (rev 484) @@ -53,6 +53,7 @@ { RefPtr<Buffer> responseBuf = response->getContentPart(*iter); Tiki::Debug::printf("Content Part: %s [%u bytes]\n", (*iter).c_str(), responseBuf->getUsedDataLen()); + Tiki::Debug::printf("%s\n", responseBuf->getData()); } Modified: tiki/include/Tiki/net/buffer.h =================================================================== --- tiki/include/Tiki/net/buffer.h 2007-08-22 00:39:13 UTC (rev 483) +++ tiki/include/Tiki/net/buffer.h 2007-08-22 17:46:32 UTC (rev 484) @@ -10,6 +10,8 @@ #include "Tiki/object.h" +#include <fstream> + namespace Tiki { namespace Net { @@ -17,13 +19,14 @@ class Buffer : public Object { public: - Buffer(size_t len) { + Buffer(size_t len, std::string contentType = "application/octet-stream") : m_contentType(contentType) { m_data = new uint8[len]; memset(m_data, 0, len); m_dataLen = len; m_usedDataLen = 0; } - Buffer(size_t len, uint8 *data) { + + Buffer(size_t len, uint8 *data, std::string contentType = "application/octet-stream") : m_contentType(contentType) { m_data = new uint8[len]; memset(m_data, 0, len); m_dataLen = len; @@ -31,6 +34,16 @@ memcpy(m_data, data, len); } + Buffer(std::string filename, std::string contentType, std::string fieldName = "") : m_fileName(filename), m_contentType(contentType), m_fieldName(fieldName) { + std::ifstream stream(filename.c_str(), std::ios::in | std::ios::binary); + stream.seekg(0, std::ios::end); + m_dataLen = m_usedDataLen = stream.tellg(); + stream.seekg(0); + m_data = new uint8[m_dataLen]; + stream.read((char *)m_data, m_dataLen); + stream.close(); + } + void append(RefPtr<Buffer> buf) { uint8 * newbuf = new uint8[ m_dataLen + buf->getDataLen() ]; memcpy(newbuf, m_data, m_usedDataLen); @@ -50,6 +63,29 @@ return m_data; } + std::string getContentType() const { + return m_contentType; + } + + std::string getFileName() const { + return m_fileName; + } + + std::string getFileNameShort() const { + std::string filename = m_fileName; + while(filename.find("/") != std::string::npos) { + filename = filename.substr(filename.find("/") + 1); + } + while(filename.find("\\") != std::string::npos) { + filename = filename.substr(filename.find("\\") + 1); + } + return filename; + } + + std::string getFieldName() const { + return m_fieldName; + } + size_t getDataLen() const { return m_dataLen; } @@ -73,6 +109,9 @@ } private: + std::string m_contentType; + std::string m_fileName; + std::string m_fieldName; uint8 *m_data; size_t m_dataLen; size_t m_usedDataLen; Modified: tiki/include/Tiki/net/http/request.h =================================================================== --- tiki/include/Tiki/net/http/request.h 2007-08-22 00:39:13 UTC (rev 483) +++ tiki/include/Tiki/net/http/request.h 2007-08-22 17:46:32 UTC (rev 484) @@ -38,8 +38,13 @@ std::list<std::string> getContentPartNames() const; RefPtr<Buffer> getContentPart(std::string name) const; + std::string getBoundaryMarker() const { + return m_boundaryMarker; + } + private: std::string m_url; + std::string m_boundaryMarker; typedef std::map<std::string, std::string> StringStringMap; typedef std::map<std::string, RefPtr< Buffer > > StringBufferMap; StringStringMap m_params; Modified: tiki/include/Tiki/net/http/useragent.h =================================================================== --- tiki/include/Tiki/net/http/useragent.h 2007-08-22 00:39:13 UTC (rev 483) +++ tiki/include/Tiki/net/http/useragent.h 2007-08-22 17:46:32 UTC (rev 484) @@ -9,6 +9,7 @@ #define __TIKI_NET_HTTP_USERAGENT_H #include "Tiki/refcnt.h" +#include "Tiki/net/tcpsocket.h" #include "Tiki/net/http/cookie.h" #include "Tiki/net/http/request.h" #include "Tiki/net/http/response.h" @@ -19,6 +20,8 @@ namespace Http { +using Tiki::Net::TCP::TCPSocket; + class HttpUserAgent : public RefCnt { public: @@ -52,9 +55,9 @@ return m_cookies; } - RefPtr<Response> get(RefPtr<Request> req) const; + RefPtr<Response> get(RefPtr<Request> req); - RefPtr<Response> post(RefPtr<Request> req) const; + RefPtr<Response> post(RefPtr<Request> req); private: std::string m_userAgentName; @@ -62,6 +65,11 @@ int m_proxyPort; std::list< RefPtr< Cookie > > m_cookies; + void parseUrl(const std::string url, std::string &host, std::string &resource, int &port); + void buildRequest(const std::string host, const std::string resource, const int port, + const std::string mode, RefPtr<Request> request, std::string &requestText, + RefPtr<Address> address); + void readResponse(RefPtr<Response> response, RefPtr<TCPSocket> socket); }; Modified: tiki/src/net/http/request.cpp =================================================================== --- tiki/src/net/http/request.cpp 2007-08-22 00:39:13 UTC (rev 483) +++ tiki/src/net/http/request.cpp 2007-08-22 17:46:32 UTC (rev 484) @@ -20,6 +20,8 @@ Request::Request() { setHeaderParam("Connection", "close"); + m_boundaryMarker = "-----------------------09f911019d74e35bd84156c5635688c0"; + } void Request::setHeaderParam(std::string param, std::string value) { Modified: tiki/src/net/http/useragent.cpp =================================================================== --- tiki/src/net/http/useragent.cpp 2007-08-22 00:39:13 UTC (rev 483) +++ tiki/src/net/http/useragent.cpp 2007-08-22 17:46:32 UTC (rev 484) @@ -11,6 +11,7 @@ #include "Tiki/net/http/useragent.h" #include <sstream> +#include <math.h> namespace Tiki { @@ -47,79 +48,209 @@ setProxyPort(8080); } -RefPtr<Response> HttpUserAgent::get(RefPtr<Request> req) const { +RefPtr<Response> HttpUserAgent::get(RefPtr<Request> req) { RefPtr<TCPSocket> socket = new TCPSocket(); socket->setNonBlocking(false); RefPtr<Response> response = new Response(); response->setUrl(req->getUrl()); response->setResultCode(200); - std::string url = req->getUrl(); - std::string hostname = ""; - int port = 80; - std::string resource = "/index.html"; + std::string hostname; + int port; + std::string resource; - if(url.find("http://") == 0) { - url = url.substr(std::string("http://").length()); + parseUrl(req->getUrl(), hostname, resource, port); + + RefPtr<Address> requestAddress = new Address(); + + std::string requestText; + buildRequest(hostname, resource, port, "GET", req, requestText, requestAddress); + socket->setPeerAddress(requestAddress); + Tiki::Debug::printf("Request:\n%s", requestText.c_str()); + + socket->open(); + if(socket->isOpen()) { + Tiki::Debug::printf("Sending request...\n"); } - else if(url.find("https://") == 0) { - url = url.substr(std::string("https://").length()); + else { + Tiki::Debug::printf("connect failed\n"); + response->setResultCode(504); + return response; } - hostname = url.substr(0, url.find("/")); - if(url.find("/") != std::string::npos) { - resource = url.substr(url.find("/")); + + RefPtr<Buffer> buf = new Buffer(2048); + buf->setData((uint8 *)requestText.c_str(), requestText.size()); + socket->send(buf); + + readResponse(response, socket); + + return response; +} + +RefPtr<Response> HttpUserAgent::post(RefPtr<Request> req) { + RefPtr<TCPSocket> socket = new TCPSocket(); + socket->setNonBlocking(false); + RefPtr<Response> response = new Response(); + response->setUrl(req->getUrl()); + response->setResultCode(200); + + std::string hostname; + int port; + std::string resource; + + parseUrl(req->getUrl(), hostname, resource, port); + + RefPtr<Address> requestAddress = new Address(); + + std::string requestText; + buildRequest(hostname, resource, port, "POST", req, requestText, requestAddress); + socket->setPeerAddress(requestAddress); + Tiki::Debug::printf("Request:\n%s", requestText.c_str()); + + socket->open(); + if(socket->isOpen()) { + Tiki::Debug::printf("Sending request...\n"); } - if(hostname.find(":") != std::string::npos) { - std::string portstr = url.substr(hostname.find(":")); + else { + Tiki::Debug::printf("connect failed\n"); + response->setResultCode(504); + return response; + } + + RefPtr<Buffer> buf = new Buffer(2048); + buf->setData((uint8 *)requestText.c_str(), requestText.size()); + socket->send(buf); + + std::list<std::string> content = req->getContentPartNames(); + if(content.size() > 1) { + for(std::list<std::string>::iterator iter = content.begin(); + iter != content.end(); + ++iter) { + RefPtr<Buffer> buf = req->getContentPart(*iter); + std::stringstream temp; + temp << req->getBoundaryMarker() << "\r\n"; + temp << "Content-Disposition: form-data: name=\""; + if(buf->getFieldName().size() > 0) { + temp << buf->getFieldName(); + } + else { + temp << "File"; + } + temp << "\"; filename=\"" << buf->getFileNameShort() << "\"\r\nContent-Type: " << buf->getContentType() << "\r\n"; + RefPtr<Buffer> headerBuf = new Buffer(2048); + std::string headerText = temp.str(); + headerBuf->setData((uint8 *)headerText.c_str(), headerText.size()); + socket->send(headerBuf); + socket->send(buf); + } + std::string footerText = req->getBoundaryMarker(); + footerText.append("--\r\n"); + RefPtr<Buffer> footerBuf = new Buffer(2048); + footerBuf->setData((uint8 *)footerText.c_str(), footerText.size()); + socket->send(footerBuf); + } + else if(content.size() == 1) { + RefPtr<Buffer> buf = req->getContentPart(*content.begin()); + socket->send(buf); + } + + readResponse(response, socket); + + return response; +} + +void HttpUserAgent::parseUrl(const std::string url, std::string &host, std::string &resource, int &port) { + std::string temp_url = url; + + // set defaults + host = ""; + port = 80; + resource = "/index.html"; + + if(temp_url.find("http://") == 0) { + temp_url = temp_url.substr(std::string("http://").length()); + } + else if(temp_url.find("https://") == 0) { + temp_url = temp_url.substr(std::string("https://").length()); + } + host = temp_url.substr(0, temp_url.find("/")); + if(temp_url.find("/") != std::string::npos) { + resource = temp_url.substr(temp_url.find("/")); + } + if(host.find(":") != std::string::npos) { + std::string portstr = url.substr(host.find(":")); port = atoi(portstr.c_str()); - hostname = hostname.substr(0, hostname.find(":")); + host = host.substr(0, host.find(":")); } +} - RefPtr<Address> requestAddress = new Address(); +void HttpUserAgent::buildRequest(const std::string host, const std::string resource, const int port, + const std::string mode, RefPtr<Request> request, std::string &requestText, + RefPtr<Address> address) { - std::stringstream request; + std::stringstream req; if(m_proxyHost.empty()) { - request << "GET " << resource << " HTTP/1.1\r\n"; - request << "Host: " << hostname << "\r\n"; - requestAddress->setHostName(hostname); - requestAddress->setPort(port); + req << mode << " " << resource << " HTTP/1.1\r\n"; + req << "Host: " << host << "\r\n"; + address->setHostName(host); + address->setPort(port); } else { // proxy connection - request << "GET " << req->getUrl(); + req << mode << " " << request->getUrl(); if(port != 80) { - request << ":" << port; + req << ":" << port; } - request << " HTTP/1.1\r\n"; - request << "Host: " << hostname << "\r\n"; - requestAddress->setHostName(m_proxyHost); - requestAddress->setPort(m_proxyPort); + req << " HTTP/1.1\r\n"; + req << "Host: " << host << "\r\n"; + address->setHostName(m_proxyHost); + address->setPort(m_proxyPort); } - std::list<std::string> params = req->getHeaderParamNames(); + std::list<std::string> params = request->getHeaderParamNames(); for(std::list<string>::const_iterator param = params.begin(); param != params.end(); ++param) { - request << *param << ": " << req->getHeaderParam(*param) << "\r\n"; + req << *param << ": " << request->getHeaderParam(*param) << "\r\n"; } - request << "\r\n"; - socket->setPeerAddress(requestAddress); - Tiki::Debug::printf("Request:\n%s", request.str().c_str()); - socket->open(); - if(socket->isOpen()) { - Tiki::Debug::printf("Sending request...\n"); + std::list<std::string> content = request->getContentPartNames(); + if(!mode.compare("POST") && content.size() > 1) { + uint64 totalSize = request->getBoundaryMarker().size() + 4; // add 4 to account for --\r\n + for(std::list<std::string>::iterator iter = content.begin(); + iter != content.end(); + ++iter) { + RefPtr<Buffer> buf = request->getContentPart(*iter); + totalSize += buf->getUsedDataLen(); + std::stringstream temp; + temp << "Content-Disposition: form-data: name=\""; + if(buf->getFieldName().size() > 0) { + temp << buf->getFieldName(); + } + else { + temp << "File"; + } + temp << "\"; filename=\"" << buf->getFileNameShort() << "\"\r\nContent-Type: " << buf->getContentType() << "\r\n"; + + // add section header size + totalSize += temp.str().size(); + } + + req << "Content-Length: " << totalSize << "\r\n"; + req << "Expect: 100-continue\r\n"; + req << "Content-Type: multipart/form-data; boundary=" << request->getBoundaryMarker() << "\r\n"; } - else { - Tiki::Debug::printf("connect failed\n"); - response->setResultCode(504); - return response; + else if(!mode.compare("POST") && content.size() == 1) { + RefPtr<Buffer> buf = request->getContentPart(*content.begin()); + req << "Content-Type: " << buf->getContentType() << "\r\n"; + req << "Content-Length: " << buf->getUsedDataLen() << "\r\n"; } + req << "\r\n"; - RefPtr<Buffer> buf = new Buffer(2048); - std::string requeststr = request.str(); - buf->setData((uint8 *)requeststr.c_str(), requeststr.size()); - socket->send(buf); + Tiki::Debug::printf("Request Text: %s\n", req.str().c_str()); + requestText = req.str(); +} +void HttpUserAgent::readResponse(RefPtr<Response> response, RefPtr<TCPSocket> socket) { std::string status = ""; READ_ONE_LINE(status, socket) @@ -189,7 +320,7 @@ else { continue; } - sizeDecoded += (ch * pow(16.0f, size.size() - i - 1)); + sizeDecoded += (ch * static_cast<int>(pow(16.0f, size.size() - i - 1))); } //Tiki::Debug::printf("chunk size: %d [%s]\n", sizeDecoded, size.c_str()); if(sizeDecoded > 0) { @@ -236,14 +367,8 @@ Tiki::Debug::printf("Encoding is unknown\n"); } response->addContentPart(DEFAULT_CONTENT_PART, fullBuf); - - return response; } -RefPtr<Response> HttpUserAgent::post(RefPtr<Request> req) const { - return NULL; -} - }; // namespace Http }; // namespace Net This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |