Back to index

nordugrid-arc-nox  1.1.0~rc6
PayloadHTTP.cpp
Go to the documentation of this file.
00001 // The code in this file is quate a mess. It is subject to cleaning 
00002 // and simplification as soon as possible. Functions must be simplified
00003 // and functionality to be split into more functions.
00004 // Some methods of this class must be called in proper order to have
00005 // it function properly. A lot of proptections to be added. 
00006 
00007 #ifdef HAVE_CONFIG_H
00008 #include <config.h>
00009 #endif
00010 
00011 #include <stdio.h>
00012 
00013 #include "PayloadHTTP.h"
00014 #include <arc/StringConv.h>
00015 
00016 namespace Arc {
00017 
00018 static std::string empty_string("");
00019 
00020 static bool ParseHTTPVersion(const std::string& s,int& major,int& minor) {
00021   major=0; minor=0;
00022   const char* p = s.c_str();
00023   if(strncasecmp(p,"HTTP/",5) != 0) return false;
00024   p+=5;
00025   char* e;
00026   major=strtol(p,&e,10);
00027   if(*e != '.') { major=0; return false; };
00028   p=e+1;
00029   minor=strtol(p,&e,10);
00030   if(*e != 0) { major=0; minor=0; return false; };
00031   return true;
00032 }
00033 
00034 // Assuming there are no zeroes in stream
00035 bool PayloadHTTP::readline(std::string& line) {
00036   line.resize(0);
00037   for(;;) {
00038     char* p = strchr(tbuf_,'\n');
00039     if(p) {
00040       *p=0;
00041       line+=tbuf_;
00042       tbuflen_-=(p-tbuf_)+1;
00043       memmove(tbuf_,p+1,tbuflen_+1); 
00044       if(line[line.length()-1] == '\r') line.resize(line.length()-1);
00045       return true;
00046     };
00047     line+=tbuf_;
00048     tbuflen_=sizeof(tbuf_)-1;
00049     if(!stream_->Get(tbuf_,tbuflen_)) break;
00050     tbuf_[tbuflen_]=0;
00051   }; 
00052   tbuf_[tbuflen_]=0;
00053   return false;
00054 }
00055 
00056 bool PayloadHTTP::parse_header(void) {
00057   method_.resize(0);
00058   code_=0;
00059   keep_alive_=false;
00060   // Skip empty lines
00061   std::string line;
00062   for(;line.empty();) if(!readline(line)) {
00063     method_="END";  // Special name to repsent closed connection
00064     chunked_=false; length_=0;
00065     return true;
00066   };
00067   // Parse request/response line
00068   std::string::size_type pos2 = line.find(' ');
00069   if(pos2 == std::string::npos) return false;
00070   std::string word1 = line.substr(0,pos2);
00071   // Identify request/response
00072   if(ParseHTTPVersion(line.substr(0,pos2),version_major_,version_minor_)) {
00073     // Response
00074     std::string::size_type pos3 = line.find(' ',pos2+1);
00075     if(pos3 == std::string::npos) return false;
00076     code_=strtol(line.c_str()+pos2+1,NULL,10);
00077     reason_=line.substr(pos3+1);
00078   } else {
00079     // Request
00080     std::string::size_type pos3 = line.rfind(' ');
00081     if((pos3 == pos2) || (pos2 == std::string::npos)) return false;
00082     if(!ParseHTTPVersion(line.substr(pos3+1),version_major_,version_minor_)) return false;
00083     method_=line.substr(0,pos2);
00084     uri_=line.substr(pos2+1,pos3-pos2-1);
00085   };
00086   if((version_major_ > 1) || ((version_major_ == 1) && (version_minor_ >= 1))) {
00087     keep_alive_=true;
00088   };
00089   // Parse header lines
00090   for(;readline(line) && (!line.empty());) {
00091     std::string::size_type pos = line.find(':');
00092     if(pos == std::string::npos) continue;
00093     std::string name = line.substr(0,pos);
00094     for(++pos;pos<line.length();++pos) if(!isspace(line[pos])) break;
00095     if(pos<line.length()) {
00096       std::string value = line.substr(pos);
00097       // for(std::string::size_type p=0;p<value.length();++p) value[p]=tolower(value[p]);
00098       Attribute(name,value);
00099     } else {
00100       Attribute(name,"");
00101     };
00102   };
00103   length_=-1; chunked_=false;
00104   std::map<std::string,std::string>::iterator it;
00105   it=attributes_.find("content-length");
00106   if(it != attributes_.end()) {
00107     length_=strtoll(it->second.c_str(),NULL,10);
00108   };
00109   it=attributes_.find("content-range");
00110   if(it != attributes_.end()) {
00111     const char* token = it->second.c_str();
00112     const char* p = token; for(;*p;p++) if(isspace(*p)) break;
00113     int64_t range_start,range_end,entity_size;
00114     if(strncasecmp("bytes",token,p-token) == 0) {
00115       for(;*p;p++) if(!isspace(*p)) break;
00116       char *e;
00117       range_start=strtoull(p,&e,10);
00118       if((*e) == '-') {
00119         p=e+1; range_end=strtoull(p,&e,10); p=e;
00120         if(((*e) == '/') || ((*e) == 0)) {
00121           if(range_start <= range_end) {
00122             offset_=range_start;
00123           };
00124           if((*p) == '/') {
00125             p++; entity_size=strtoull(p,&e,10);
00126             if((*e) == 0) {
00127               size_=entity_size;
00128             };
00129           };
00130         };
00131       };
00132     };
00133   };
00134   it=attributes_.find("transfer-encoding");
00135   if(it != attributes_.end()) {
00136     if(strcasecmp(it->second.c_str(),"chunked") != 0) {
00137       // Non-implemented encoding
00138       return false;
00139     };
00140     chunked_=true;
00141   };
00142   it=attributes_.find("connection");
00143   if(it != attributes_.end()) {
00144     if(strcasecmp(it->second.c_str(),"keep-alive") == 0) {
00145       keep_alive_=true;
00146     } else {
00147       keep_alive_=false;
00148     };
00149   };
00150   // In case of keep_alive (HTTP1.1) there must be length specified
00151   if(keep_alive_ && (length_ == -1)) length_=0;
00152   // If size of object was not reported then try to deduce it.
00153   if((size_ == 0) && (length_ != -1)) size_=offset_+length_;
00154   return true;
00155 }
00156 
00157 bool PayloadHTTP::read(char* buf,int64_t& size) {
00158 //char* buff = buf;
00159 //memset(buf,0,size);
00160   if(tbuflen_ >= size) {
00161     memcpy(buf,tbuf_,size);
00162     memmove(tbuf_,tbuf_+size,tbuflen_-size+1);
00163     tbuflen_-=size;
00164   } else {
00165     memcpy(buf,tbuf_,tbuflen_);
00166     buf+=tbuflen_; 
00167     int64_t l = size-tbuflen_;
00168     size=tbuflen_; tbuflen_=0; tbuf_[0]=0; 
00169     for(;l;) {
00170       int l_ = (l>INT_MAX)?INT_MAX:l;
00171       if(!stream_->Get(buf,l_)) return (size>0);
00172       size+=l_; buf+=l_; l-=l_;
00173     };
00174   };
00175   return true;
00176 }
00177 
00178 bool PayloadHTTP::get_body(void) {
00179   if(fetched_) return true; // Already fetched body
00180   fetched_=true; // Even attempt counts
00181   valid_=false; // But object is invalid till whole body is available
00182   // TODO: Check for methods and responses which can't have body
00183   char* result = NULL;
00184   int64_t result_size = 0;
00185   if(chunked_) {
00186     for(;;) {
00187       std::string line;
00188       if(!readline(line)) return false;
00189       char* e;
00190       int64_t chunk_size = strtoll(line.c_str(),&e,16);
00191       if((*e != ';') && (*e != 0)) { free(result); return false; };
00192       if(e == line.c_str()) { free(result); return false; };
00193       if(chunk_size == 0) break;
00194       char* new_result = (char*)realloc(result,result_size+chunk_size+1);
00195       if(new_result == NULL) { free(result); return false; };
00196       result=new_result;
00197       if(!read(result+result_size,chunk_size)) { free(result); return false; };
00198       result_size+=chunk_size;
00199       if(!readline(line)) return false;
00200       if(!line.empty()) return false;
00201     };
00202   } else if(length_ == 0) {
00203     valid_=true;
00204     return true;
00205   } else if(length_ > 0) {
00206     result=(char*)malloc(length_+1);
00207     if(!read(result,length_)) { free(result); return false; };
00208     result_size=length_;
00209   } else {
00210     // Read till connection closed
00211     for(;;) {
00212       int64_t chunk_size = 4096;
00213       char* new_result = (char*)realloc(result,result_size+chunk_size+1);
00214       if(new_result == NULL) { free(result); return false; };
00215       result=new_result;
00216       if(!read(result+result_size,chunk_size)) break;
00217       result_size+=chunk_size;
00218     };
00219   };
00220   if (result == NULL) {
00221     return false;
00222   }
00223   result[result_size]=0;
00224   // Attach result to buffer exposed to user
00225   PayloadRawBuf b;
00226   b.data=result; b.size=result_size; b.length=result_size; b.allocated=true;
00227   buf_.push_back(b);
00228   // If size of object was not reported then try to deduce it.
00229   if(size_ == 0) size_=offset_+result_size;
00230   valid_=true;
00231   return true;
00232 }
00233 
00234 const std::string& PayloadHTTP::Attribute(const std::string& name) {
00235   std::multimap<std::string,std::string>::iterator it = attributes_.find(name);
00236   if(it == attributes_.end()) return empty_string;
00237   return it->second;
00238 }
00239 
00240 const std::multimap<std::string,std::string>& PayloadHTTP::Attributes(void) {
00241   return attributes_;
00242 }
00243 
00244 void PayloadHTTP::Attribute(const std::string& name,const std::string& value) {
00245   attributes_.insert(std::pair<std::string,std::string>(lower(name),value));
00246 }
00247 
00248 PayloadHTTP::PayloadHTTP(PayloadStreamInterface& stream,bool own):valid_(false),stream_(&stream),stream_own_(own),fetched_(false),stream_offset_(0),chunked_size_(0),chunked_offset_(0),rbody_(NULL),sbody_(NULL),body_own_(false),keep_alive_(true) {
00249   tbuf_[0]=0; tbuflen_=0;
00250   if(!parse_header()) return;
00251   // If stream_ is owned then body can be fetched later
00252   // if(!stream_own_) if(!get_body()) return;
00253   valid_=true;
00254 }
00255 
00256 PayloadHTTP::PayloadHTTP(const std::string& method,const std::string& url,PayloadStreamInterface& stream):valid_(true),fetched_(true),stream_offset_(0),chunked_size_(0),chunked_offset_(0),stream_(&stream),stream_own_(false),rbody_(NULL),sbody_(NULL),body_own_(false),uri_(url),method_(method),keep_alive_(true) {
00257   version_major_=1; version_minor_=1;
00258   // TODO: encode URI properly
00259 }
00260 
00261 PayloadHTTP::PayloadHTTP(int code,const std::string& reason,PayloadStreamInterface& stream):valid_(true),fetched_(true),stream_offset_(0),chunked_size_(0),chunked_offset_(0),stream_(&stream),stream_own_(false),rbody_(NULL),sbody_(NULL),body_own_(false),code_(code),reason_(reason),keep_alive_(true) {
00262   version_major_=1; version_minor_=1;
00263   if(reason_.empty()) reason_="OK";
00264 }
00265 
00266 PayloadHTTP::PayloadHTTP(const std::string& method,const std::string& url):valid_(true),fetched_(true),stream_offset_(0),chunked_size_(0),chunked_offset_(0),stream_(NULL),stream_own_(false),rbody_(NULL),sbody_(NULL),body_own_(false),uri_(url),method_(method),keep_alive_(true) {
00267   version_major_=1; version_minor_=1;
00268   // TODO: encode URI properly
00269 }
00270 
00271 PayloadHTTP::PayloadHTTP(int code,const std::string& reason):valid_(true),fetched_(true),stream_offset_(0),chunked_size_(0),chunked_offset_(0),stream_(NULL),stream_own_(false),rbody_(NULL),sbody_(NULL),body_own_(false),code_(code),reason_(reason),keep_alive_(true) {
00272   version_major_=1; version_minor_=1;
00273   if(reason_.empty()) reason_="OK";
00274 }
00275 
00276 PayloadHTTP::~PayloadHTTP(void) {
00277   if(rbody_ && body_own_) delete rbody_;
00278   if(sbody_ && body_own_) delete sbody_;
00279   if(stream_ && stream_own_) delete stream_;
00280 }
00281 
00282 bool PayloadHTTP::Flush(void) {
00283   std::string header;
00284   bool to_stream = (stream_ != NULL);
00285   if(method_.empty() && (code_ == 0)) return false;
00286   // Computing length of Body part
00287   length_=0;
00288   std::string range_header;
00289   if((method_ != "GET") && (method_ != "HEAD")) {
00290     int64_t start = 0;
00291     if(sbody_) {
00292       if(sbody_->Limit() > sbody_->Pos()) {
00293         length_ = sbody_->Limit() - sbody_->Pos();
00294       };
00295       start=sbody_->Pos();
00296     } else {
00297       for(int n=0;;++n) {
00298         if(Buffer(n) == NULL) break;
00299         length_+=BufferSize(n);
00300       };
00301       start=BufferPos(0);
00302     };
00303     if(length_ != Size()) {
00304       // Add range definition if Body represents part of logical buffer size
00305       // and adjust HTTP code accordingly
00306       int64_t end = start+length_;
00307       std::string length_str;
00308       std::string range_str;
00309       if(end <= Size()) {
00310         length_str=tostring(Size());
00311       } else {
00312         length_str="*";
00313       }; 
00314       if(end > start) {
00315         range_str=tostring(start)+"-"+tostring(end-1);
00316         if(code_ == HTTP_OK) {
00317           code_=HTTP_PARTIAL;
00318           reason_="Partial content";
00319         };
00320       } else {
00321         range_str="*";
00322         if(code_ == HTTP_OK) {
00323           code_=HTTP_RANGE_NOT_SATISFIABLE;
00324           reason_="Range not satisfiable";
00325         };
00326       };
00327       range_header="Content-Range: bytes "+range_str+"/"+length_str+"\r\n";
00328     };
00329     range_header+="Content-Length: "+tostring(length_)+"\r\n";
00330   };
00331   // Starting header
00332   if(!method_.empty()) {
00333     header=method_+" "+uri_+
00334            " HTTP/"+tostring(version_major_)+"."+tostring(version_minor_)+"\r\n";
00335   } else if(code_ != 0) {
00336     char tbuf[256]; tbuf[255]=0;
00337     snprintf(tbuf,255,"HTTP/%i.%i %i",version_major_,version_minor_,code_);
00338     header="HTTP/"+tostring(version_major_)+"."+tostring(version_minor_)+" "+
00339            tostring(code_)+" "+reason_+"\r\n";
00340   };
00341   if((version_major_ == 1) && (version_minor_ == 1) && (!method_.empty())) {
00342     std::map<std::string,std::string>::iterator it = attributes_.find("host");
00343     if(it == attributes_.end()) {
00344       std::string host;
00345       if(!uri_.empty()) {
00346         std::string::size_type p1 = uri_.find("://");
00347         if(p1 != std::string::npos) {
00348           std::string::size_type p2 = uri_.find('/',p1+3);
00349           if(p2 != std::string::npos) {
00350             host=uri_.substr(p1+3,p2-p1-3);
00351           };
00352         };
00353       };
00354       header+="Host: "+host+"\r\n";
00355     };
00356   };
00357   // Adding previously generated range specifier
00358   header+=range_header;
00359   bool keep_alive = false;
00360   if((version_major_ == 1) && (version_minor_ == 1)) keep_alive=keep_alive_;
00361   if(keep_alive) {
00362     header+="Connection: keep-alive\r\n";
00363   } else {
00364     header+="Connection: close\r\n";
00365   };
00366   for(std::map<std::string,std::string>::iterator a = attributes_.begin();a!=attributes_.end();++a) {
00367     header+=(a->first)+": "+(a->second)+"\r\n";
00368   };
00369   header+="\r\n";
00370   if(to_stream) {
00371     if(!stream_->Put(header)) return false;
00372     if(length_ > 0) {
00373       if(sbody_) {
00374         // stream to stream transfer
00375         // TODO: choose optimal buffer size
00376         int tbufsize = (length_>1024*1024)?(1024*1024):length_;
00377         char* tbuf = new char[tbufsize];
00378         if(!tbuf) return false;
00379         for(;;) {
00380           int lbuf = tbufsize;
00381           if(!sbody_->Get(tbuf,lbuf)) break;
00382           if(!stream_->Put(tbuf,lbuf)) { delete[] tbuf; return false; };
00383         };
00384         delete[] tbuf;
00385       } else {
00386         for(int n=0;;++n) {
00387           char* tbuf = Buffer(n);
00388           if(tbuf == NULL) break;
00389           int64_t lbuf = BufferSize(n);
00390           if(lbuf > 0) if(!stream_->Put(tbuf,lbuf)) return false;
00391         };
00392       };
00393     };
00394     //if(!keep_alive) stream_->Close();
00395   } else {
00396     Insert(header.c_str(),0,header.length());
00397   };
00398   return true;
00399 }
00400 
00401 void PayloadHTTP::Body(PayloadRawInterface& body,bool ownership) {
00402   if(rbody_ && body_own_) delete rbody_;
00403   if(sbody_ && body_own_) delete sbody_;
00404   sbody_ = NULL;
00405   rbody_=&body; body_own_=ownership;
00406 }
00407 
00408 void PayloadHTTP::Body(PayloadStreamInterface& body,bool ownership) {
00409   if(rbody_ && body_own_) delete rbody_;
00410   if(sbody_ && body_own_) delete sbody_;
00411   rbody_ = NULL;
00412   sbody_=&body; body_own_=ownership;
00413 }
00414 
00415 char PayloadHTTP::operator[](PayloadRawInterface::Size_t pos) const {
00416   if(!((PayloadHTTP*)this)->get_body()) return 0;
00417   if(pos < PayloadRaw::Size()) {
00418     return PayloadRaw::operator[](pos);
00419   };
00420   if(rbody_) {
00421     return rbody_->operator[](pos-Size());
00422   };
00423   if(sbody_) {
00424     // Not supporting direct read from stream body
00425   };
00426   return 0;
00427 }
00428 
00429 char* PayloadHTTP::Content(PayloadRawInterface::Size_t pos) {
00430   if(!get_body()) return NULL;
00431   if(pos < PayloadRaw::Size()) {
00432     return PayloadRaw::Content(pos);
00433   };
00434   if(rbody_) {
00435     return rbody_->Content(pos-Size());
00436   };
00437   if(sbody_) {
00438     // Not supporting content from stream body
00439   };
00440   return NULL;
00441 }
00442 
00443 PayloadRawInterface::Size_t PayloadHTTP::Size(void) const {
00444   if(!((PayloadHTTP*)this)->get_body()) return 0;
00445   if(rbody_) {
00446     return PayloadRaw::Size() + (rbody_->Size());
00447   };
00448   if(sbody_) {
00449     return PayloadRaw::Size() + (sbody_->Size());
00450   };
00451   return PayloadRaw::Size();
00452 }
00453 
00454 char* PayloadHTTP::Insert(PayloadRawInterface::Size_t pos,PayloadRawInterface::Size_t size) {
00455   if(!get_body()) return NULL;
00456   return PayloadRaw::Insert(pos,size);
00457 }
00458 
00459 char* PayloadHTTP::Insert(const char* s,PayloadRawInterface::Size_t pos,PayloadRawInterface::Size_t size) {
00460   if(!get_body()) return NULL;
00461   return PayloadRaw::Insert(s,pos,size);
00462 }
00463 
00464 char* PayloadHTTP::Buffer(unsigned int num) {
00465   if(!get_body()) return NULL;
00466   if(num < buf_.size()) {
00467     return PayloadRaw::Buffer(num);
00468   };
00469   if(rbody_) {
00470     return rbody_->Buffer(num-buf_.size());
00471   };
00472   if(sbody_) {
00473     // Not supporting buffer access to stream body
00474   };
00475   return NULL;
00476 }
00477 
00478 PayloadRawInterface::Size_t PayloadHTTP::BufferSize(unsigned int num) const {
00479   if(!((PayloadHTTP*)this)->get_body()) return 0;
00480   if(num < buf_.size()) {
00481     return PayloadRaw::BufferSize(num);
00482   };
00483   if(rbody_) {
00484     return rbody_->BufferSize(num-buf_.size());
00485   };
00486   if(sbody_) {
00487     // Not supporting buffer access to stream body
00488   };
00489   return 0;
00490 }
00491 
00492 PayloadRawInterface::Size_t PayloadHTTP::BufferPos(unsigned int num) const {
00493   if(!((PayloadHTTP*)this)->get_body()) return 0;
00494   if(num < buf_.size()) {
00495     return PayloadRaw::BufferPos(num);
00496   };
00497   if(rbody_) {
00498     return rbody_->BufferPos(num-buf_.size())+PayloadRaw::BufferPos(num);
00499   };
00500   if(sbody_) {
00501     // Not supporting buffer access to stream body
00502   };
00503   return PayloadRaw::BufferPos(num);
00504 }
00505 
00506 bool PayloadHTTP::Truncate(PayloadRawInterface::Size_t size) {
00507   if(!get_body()) return false;
00508   if(size < PayloadRaw::Size()) {
00509     if(rbody_ && body_own_) delete rbody_;
00510     if(sbody_ && body_own_) delete sbody_;
00511     rbody_=NULL; sbody_=NULL;
00512     return PayloadRaw::Truncate(size);
00513   };
00514   if(rbody_) {
00515     return rbody_->Truncate(size-Size());
00516   };
00517   if(sbody_) {
00518     // Stream body does not support Truncate yet
00519   };
00520   return false;
00521 }
00522 
00523 bool PayloadHTTP::Get(char* buf,int& size) {
00524   if(fetched_) {
00525     // Read from buffers
00526     uint64_t bo = 0;
00527     for(int num = 0;num<buf_.size();++num) {
00528       uint64_t bs = PayloadRaw::BufferSize(num);
00529       if((bo+bs) > stream_offset_) {
00530         char* p = PayloadRaw::Buffer(num);
00531         p+=(stream_offset_-bo);
00532         bs-=(stream_offset_-bo);
00533         if(bs>size) bs=size;
00534         memcpy(buf,p,bs);
00535         size=bs; stream_offset_+=bs;
00536         return true;
00537       };
00538       bo+=bs;
00539     };
00540     if(rbody_) {
00541       for(int num = 0;;++num) {
00542         char* p = PayloadRaw::Buffer(num);
00543         if(!p) break;
00544         uint64_t bs = PayloadRaw::BufferSize(num);
00545         if((bo+bs) > stream_offset_) {
00546           p+=(stream_offset_-bo);
00547           bs-=(stream_offset_-bo);
00548           if(bs>size) bs=size;
00549           memcpy(buf,p,bs);
00550           size=bs; stream_offset_+=bs;
00551           return true;
00552         };
00553         bo+=bs;
00554       };
00555     } else if(sbody_) {
00556       if(sbody_->Get(buf,size)) {
00557         stream_offset_+=size;
00558         return true;
00559       };
00560     };
00561     return false;
00562   };
00563     // TODO: Check for methods and responses which can't have body
00564   if(chunked_) {
00565     if(chunked_size_ == -1) { // chunked stream is over
00566       size=0;
00567       return false;
00568     };
00569     if(chunked_size_ == chunked_offset_) {
00570       // read chunk size
00571       std::string line;
00572       if(!readline(line)) return false;
00573       char* e;
00574       chunked_size_ = strtoll(line.c_str(),&e,16);
00575       if(((*e != ';') && (*e != 0)) || (e == line.c_str())) {
00576         chunked_size_=-1; // No more stream
00577         valid_=false; // Object becomes invalid
00578         size=0;
00579         return false;
00580       };
00581       chunked_offset_=0;
00582       if(chunked_size_ == 0) {
00583         // end of stream
00584         chunked_size_=-1; size=0;
00585         return false;
00586       };
00587     };
00588     // read chunk content
00589     int64_t bs = chunked_size_-chunked_offset_;
00590     if(bs > size) bs=size;
00591     if(!read(buf,bs)) { size=bs; return false; };
00592     chunked_offset_+=bs;
00593     size=bs; stream_offset_+=bs;
00594     return true;
00595   };
00596   if(length_ == 0) {
00597     // No body
00598     size=0;
00599     return false;
00600   };
00601   if(length_ > 0) {
00602     // Ordinary stream with known length
00603     int64_t bs = length_-stream_offset_;
00604     if(bs == 0) { size=0; return false; }; // End of content
00605     if(bs > size) bs=size;
00606     if(!read(buf,bs)) {
00607       valid_=false; // This is not expected, hence invalidate object
00608       size=bs; return false;
00609     };
00610     size=bs; stream_offset_+=bs;
00611     return true;
00612   };
00613   // Ordinary stream with no length known
00614   int64_t tsize = size;
00615   bool r = read(buf,tsize);
00616   if(r) stream_offset_+=tsize;
00617   size=tsize;
00618   // TODO: adjust logical parameters of buffers
00619   return r;
00620 }
00621 
00622 bool PayloadHTTP::Get(std::string& buf) {
00623   char tbuf[1024];
00624   int l = sizeof(tbuf);
00625   bool result = Get(tbuf,l);
00626   buf.assign(tbuf,l);
00627   return result;
00628 }
00629 
00630 std::string PayloadHTTP::Get(void) {
00631   std::string s;
00632   Get(s);
00633   return s;
00634 }
00635 
00636 // Stream interface is meant to be used only
00637 // for reading HTTP body.
00638 bool PayloadHTTP::Put(const char* buf,PayloadStreamInterface::Size_t size) {
00639   return false;
00640 }
00641 
00642 bool PayloadHTTP::Put(const std::string& buf) {
00643   return false;
00644 }
00645 
00646 bool PayloadHTTP::Put(const char* buf) {
00647   return false;
00648 }
00649 
00650 int PayloadHTTP::Timeout(void) const {
00651   if(!stream_) return 0;
00652   return stream_->Timeout();
00653 }
00654 
00655 void PayloadHTTP::Timeout(int to) {
00656   if(stream_) stream_->Timeout(to);
00657 }
00658 
00659 PayloadStreamInterface::Size_t PayloadHTTP::Pos(void) const {
00660   if(!stream_) return 0;
00661   return offset_+stream_offset_;
00662 }
00663 
00664 PayloadStreamInterface::Size_t PayloadHTTP::Limit(void) const {
00665   return Size();
00666 }
00667 
00668 } // namespace Arc
00669