|
From: Christian P. <cp...@us...> - 2005-01-07 13:41:33
|
Update of /cvsroot/pclasses/pclasses2/src/Net In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv4968/src/Net Added Files: HTTPClient.cpp HTTPHeader.cpp Log Message: Added HTTPHeader, HTTPRequestHeader, HTTPResponseHeader, HTTPRequest, HTTPResponse, HTTPClient. --- NEW FILE: HTTPHeader.cpp --- /*************************************************************************** * Copyright (C) 2004 by Christian Prochnow * * cp...@se... * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "pclasses/Net/HTTPHeader.h" namespace P { namespace Net { HTTPHeader::HTTPHeader() { } HTTPHeader::~HTTPHeader() { } const std::string& HTTPHeader::get(const std::string& head) const { static std::string empty; const_iterator i = _values.find(head); if(i != _values.end()) return i->second; return empty; } void HTTPHeader::set(const std::string& head, const std::string& val) { _values[head] = val; } bool HTTPHeader::remove(const std::string& head) { iterator i = _values.find(head); if(i != _values.end()) { _values.erase(i); return true; } return false; } bool HTTPHeader::contains(const std::string& head) const { return (_values.find(head) != _values.end() ? true : false); } HTTPHeader::iterator HTTPHeader::find(const std::string& head) { return _values.find(head); } HTTPHeader::const_iterator HTTPHeader::find(const std::string& head) const { return _values.find(head); } const std::string& HTTPHeader::operator[](const std::string& head) const { return get(head); } } // !namespace Net } // !namespace P --- NEW FILE: HTTPClient.cpp --- /*************************************************************************** * Copyright (C) 2004 by Christian Prochnow * * cp...@se... * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "pclasses/pclasses-config.h" #include "pclasses/IO/IOStream.h" #include "pclasses/Net/HTTPClient.h" #include <netinet/in.h> #ifdef PCLASSES_HAVE_APPLETALK # include <netatalk/at.h> #endif #ifdef PCLASSES_HAVE_IPX # include <netipx/ipx.h> #endif #include <sstream> namespace P { namespace Net { HTTPRequest::HTTPRequest(Method method, const IO::URL& url) : _method(method), _url(url) { } HTTPRequest::~HTTPRequest() { } HTTPRequest::Method HTTPRequest::method() const throw() { return _method; } const IO::URL& HTTPRequest::url() const throw() { return _url; } const HTTPRequestHeader& HTTPRequest::header() const throw() { return _header; } HTTPRequestHeader& HTTPRequest::header() throw() { return _header; } HTTPResponse::HTTPResponse(HTTPClient& client, const std::string& proto, int code, const std::string& resp) : _client(&client), _proto(proto), _responseCode(code), _response(resp), _bytesRead(0), _contentLength(0), _chunkedEncoding(false) { setAccess(Read); setValid(true); setEof(false); } HTTPResponse::~HTTPResponse() throw() { try { close(); } catch(...) { } } const HTTPResponseHeader& HTTPResponse::header() const throw() { return _header; } HTTPResponseHeader& HTTPResponse::header() throw() { return _header; } const std::string& HTTPResponse::protocol() const throw() { return _proto; } int HTTPResponse::responseCode() const throw() { return _responseCode; } const std::string& HTTPResponse::response() const throw() { return _response; } void HTTPResponse::_close() throw(IO::IOError) { setValid(false); setAccess(None); setEof(true); _client = 0; } size_t HTTPResponse::_write(const char* buffer, size_t count) throw(IO::IOError) { return 0; } size_t HTTPResponse::_read(char* buffer, size_t count) throw(IO::IOError) { if(!_bytesRead) { HTTPHeader::const_iterator i = _header.find("Content-Length"); if(i != _header.end()) { std::istringstream is(i->second); is >> _contentLength; } i = _header.find("Transfer-Encoding"); if(i != _header.end()) { if(i->second == "chunked") _chunkedEncoding = true; } } size_t ret; if(_chunkedEncoding) { // get next chunk size if it's unknown ... if(_contentLength == 0) { _readNextLine: std::string str = _client->readLine(); if(str.empty()) { setEof(true); return 0; } else if(str == "\r\n" || str == "\n") goto _readNextLine; std::istringstream is(str); is >> std::hex >> _contentLength; if(!_contentLength) { setEof(true); return 0; } } size_t bytesLeft = _contentLength - _bytesRead; if(count > bytesLeft) count = bytesLeft; ret = _client->read(buffer, count); if(!ret) setEof(true); _bytesRead += ret; // chunk finished ? if(_bytesRead == _contentLength) { _bytesRead = 0; _contentLength = 0; } } else { // we know the size of the response body ... if(_contentLength > 0) { if(_bytesRead == _contentLength) { setEof(true); return 0; } size_t bytesLeft = _contentLength - _bytesRead; if(count > bytesLeft) count = bytesLeft; ret = _client->read(buffer, count); _bytesRead += ret; if(!ret) setEof(true); } // we do not know the size of the response body ... // the connection will probably be closed after receiving // the body else { ret = _client->read(buffer, count); _bytesRead += ret; if(!ret) setEof(true); } } return ret; } HTTPClient::Domain AddrFamily2Domain(int family) { HTTPClient::Domain d; switch(family) { case AF_INET: d = Socket::Inet; break; case AF_INET6: d = Socket::Inet6; break; case AF_IPX: d = Socket::IPX; break; case AF_APPLETALK: d = Socket::AppleTalk; break; default: throw; } return d; } HTTPClient::HTTPClient() : StreamSocket() { } HTTPClient::HTTPClient(Domain d) : StreamSocket() { open(d); } HTTPClient::HTTPClient(const NetworkAddress& addr, port_t port) : StreamSocket() { open(AddrFamily2Domain(addr.family())); connect(addr, port); } HTTPClient::~HTTPClient() throw() { } void HTTPClient::open(Domain d) throw(IO::IOError) { Socket::open(d, Stream, 0); } void HTTPClient::sendRequest(HTTPRequest& req) throw(IO::IOError) { IO::IOStream reqs(*this); switch(req.method()) { case HTTPRequest::GET: reqs << "GET "; break; case HTTPRequest::HEAD: reqs << "HEAD "; break; case HTTPRequest::POST: reqs << "POST "; break; case HTTPRequest::PUT: reqs << "PUT "; break; case HTTPRequest::DELETE: reqs << "DELETE "; break; default: throw RuntimeError("HTTP request not implemented",P_SOURCEINFO); } // send request line .. reqs << req.url().path() << " HTTP/1.1\r\n"; // send header lines ... HTTPHeader::const_iterator i = req.header().begin(); bool hostFound = false; while(i != req.header().end()) { if(i->first == "Host") hostFound = true; reqs << i->first << ": " << i->second << "\r\n"; ++i; } // "Host:" header is required in HTTP/1.1! if(!hostFound) reqs << "Host: " << req.url().host() << "\r\n"; // terminate request and flush stream reqs << "\r\n"; reqs.sync(); } HTTPResponse HTTPClient::readResponse() throw(IO::IOError) { std::string line1 = readLine(); std::string httpProto, httpResponse; int httpResponseCode; std::string tmp; std::istringstream is(line1); is >> httpProto; is >> httpResponseCode; //is >> tmp; httpCode = atoi(tmp.c_str()); is >> httpResponse; HTTPResponse resp(*this, httpProto, httpResponseCode, httpResponse); while(1) { tmp = readLine(); // response header terminated ? if(tmp == "\r\n" || tmp == "\n") break; size_t pos = tmp.find(':'); if(pos != std::string::npos && tmp.size() > 4) { std::string headName = tmp.substr(0, pos); std::string headVal = tmp.substr(pos+2, tmp.size()-(pos+4)); std::cerr << headName << '=' << headVal << std::endl; resp.header().set(headName, headVal); } } return resp; } } // !namespace Net } // !namespace P |