38
38
// -------------------- PayloadHTTP -----------------------------
40
const std::string& PayloadHTTP::Attribute(const std::string& name) {
41
std::multimap<std::string,std::string>::iterator it = attributes_.find(name);
40
const std::string& PayloadHTTP::Attribute(const std::string& name) const {
41
std::multimap<std::string,std::string>::const_iterator it = attributes_.find(name);
42
42
if(it == attributes_.end()) return empty_string;
46
const std::multimap<std::string,std::string>& PayloadHTTP::Attributes(void) {
46
const std::list<std::string> PayloadHTTP::Attributes(const std::string& name) const {
47
std::list<std::string> attrs;
48
for(std::multimap<std::string,std::string>::const_iterator attr = attributes_.begin();
49
attr != attributes_.end(); ++attr) {
50
if(attr->first == name) attrs.push_back(attr->second);
55
const std::multimap<std::string,std::string>& PayloadHTTP::Attributes(void) const {
47
56
return attributes_;
59
bool PayloadHTTP::AttributeMatch(const std::string& name, const std::string& value) const {
60
std::multimap<std::string,std::string>::const_iterator attr = attributes_.begin();
61
for(;attr != attributes_.end();++attr) {
62
if(attr->first == name) {
63
std::string sattr = Arc::lower(Arc::trim(attr->second," \r\n"));
64
if(sattr == value) return true;
50
70
PayloadHTTP::PayloadHTTP(void):
51
71
valid_(false),version_major_(1),version_minor_(1),
52
72
code_(0),length_(0),offset_(0),size_(0),end_(0),keep_alive_(true) {
445
466
if(pos3 == std::string::npos) return false;
446
467
code_=strtol(line.c_str()+pos2+1,NULL,10);
447
468
reason_=line.substr(pos3+1);
470
// TODO: skip 100 response
450
474
std::string::size_type pos3 = line.rfind(' ');
493
517
valid_=false; // But object is invalid till whole body is available
494
518
if(body_) free(body_);
495
519
body_ = NULL; body_size_ = 0;
496
// TODO: Check for methods and responses which can't have body
520
if(head_response_ && (code_ == 200)) {
521
// Successful response to HEAD contains no body
497
528
char* result = NULL;
498
529
int64_t result_size = 0;
499
530
if(length_ == 0) {
538
PayloadHTTPIn::PayloadHTTPIn(PayloadStreamInterface& stream,bool own):
539
chunked_(CHUNKED_NONE),chunk_size_(0),
569
PayloadHTTPIn::PayloadHTTPIn(PayloadStreamInterface& stream,bool own,bool head_response):
570
head_response_(head_response),chunked_(CHUNKED_NONE),chunk_size_(0),
540
571
multipart_(MULTIPART_NONE),stream_(&stream),stream_offset_(0),
541
572
stream_own_(own),fetched_(false),header_read_(false),body_read_(false),
542
573
body_(NULL),body_size_(0) {
735
766
PayloadHTTP(method,url),
736
767
head_response_(false),rbody_(NULL),sbody_(NULL),sbody_size_(0),
737
768
body_own_(false),to_stream_(false),use_chunked_transfer_(false),
769
stream_offset_(0),stream_finished_(false),
770
enable_header_out_(true), enable_body_out_(true) {
743
775
PayloadHTTP(code,reason),
744
776
head_response_(head_response),rbody_(NULL),sbody_(NULL),sbody_size_(0),
745
777
body_own_(false),to_stream_(false),use_chunked_transfer_(false),
778
stream_offset_(0), stream_finished_(false),
779
enable_header_out_(true), enable_body_out_(true) {
755
788
PayloadHTTPOutStream::PayloadHTTPOutStream(const std::string& method,const std::string& url):
756
PayloadHTTPOut(method,url),stream_finished_(false) /*,chunk_size_offset_(0)*/ {
789
PayloadHTTPOut(method,url) /*,chunk_size_offset_(0)*/ {
759
792
PayloadHTTPOutStream::PayloadHTTPOutStream(int code,const std::string& reason,bool head_response):
760
PayloadHTTPOut(code,reason,head_response),stream_finished_(false) /*,chunk_size_offset_(0)*/ {
793
PayloadHTTPOut(code,reason,head_response) /*,chunk_size_offset_(0)*/ {
763
796
PayloadHTTPOutStream::~PayloadHTTPOutStream(void) {
927
960
bool PayloadHTTPOut::Flush(PayloadStreamInterface& stream) {
929
//bool to_stream = (stream_ != NULL);
930
//bool to_stream = true;
961
if(enable_header_out_) {
962
if(!FlushHeader(stream)) return false;
964
if(enable_body_out_) {
965
if(!FlushBody(stream)) return false;
970
bool PayloadHTTPOut::FlushHeader(PayloadStreamInterface& stream) {
931
971
if(!make_header(true)) return false;
933
if(!stream.Put(header_)) {
934
error_ = IString("Failed to write header to output stream").str();
972
if(!stream.Put(header_)) {
973
error_ = IString("Failed to write header to output stream").str();
979
bool PayloadHTTPOut::FlushBody(PayloadStreamInterface& stream) {
980
// TODO: process 100 request/response
937
981
if((length_ > 0) || (use_chunked_transfer_)) {
939
983
// stream to stream transfer
1019
//if(!keep_alive) stream_->Close();
1021
// Insert(header_.c_str(),0,header.length());
1026
1066
void PayloadHTTPOutRaw::Body(PayloadRawInterface& body,bool ownership) {
1042
1082
if(pos < size) sbody_size_ = (size-pos);
1085
void PayloadHTTPOut::ResetOutput(bool enable_header, bool enable_body) {
1087
stream_finished_ = false;
1088
// Because we can't/do not want to reset state
1089
// body stream then actual body size need to be
1093
PayloadStreamInterface::Size_t pos = sbody_->Pos();
1094
PayloadStreamInterface::Size_t size = sbody_->Size();
1095
PayloadStreamInterface::Size_t limit = sbody_->Limit();
1096
if((size == 0) || (size > limit)) size = limit;
1097
if(pos < size) sbody_size_ = (size-pos);
1099
enable_header_out_ = enable_header;
1100
enable_body_out_ = enable_body;
1045
1104
char PayloadHTTPOutRaw::operator[](PayloadRawInterface::Size_t pos) const {
1046
1105
if(!((PayloadHTTPOutRaw&)(*this)).remake_header(false)) return 0;
1047
1106
if(pos == -1) pos = 0;
1197
1256
if(stream_finished_) return false;
1199
1258
uint64_t bo = 0; // buf offset
1200
uint64_t bs = header_.length(); // buf size
1259
uint64_t bs = enable_header_out_?header_.length():0; // buf size
1202
1261
if(l >= size) { size = l; return true; };
1203
1262
if((bo+bs) > stream_offset_) {
1213
1272
if(l >= size) { size = l; return true; }; // buffer is full
1274
if(rbody_ && enable_body_out_) {
1216
1275
/* This code is only needed if stream and raw are mixed.
1217
1276
Currently it is not possible hence it is not needed.
1218
1277
But code is kept for future use. Code is not tested.
1313
1372
bool PayloadHTTPOutStream::Get(PayloadStreamInterface& dest,int& size) {
1314
if(stream_offset_ > 0) return PayloadStreamInterface::Get(dest,size);
1315
if(size != -1) return PayloadStreamInterface::Get(dest,size);
1373
if((stream_offset_ > 0) || (size >= 0)) {
1374
// If it is not first call or if size control is requested
1375
// then convenience method PayloadStreamInterface::Get is
1376
// used, which finally calls PayloadHTTPOutStream::Get.
1377
return PayloadStreamInterface::Get(dest,size);
1379
// But if whole content is requested at once we use faster Flush* methods
1317
1381
return false; // stream finished
1338
1402
PayloadStreamInterface::Size_t PayloadHTTPOutStream::Limit(void) const {
1339
1403
if(!((PayloadHTTPOutStream&)(*this)).remake_header(true)) return 0;
1340
return header_.length()+body_size();
1404
PayloadStreamInterface::Size_t limit = 0;
1405
if(enable_header_out_) limit += header_.length();
1406
if(enable_body_out_) limit += body_size();
1343
1410
//-------------------------------------------------------------------