1 /*
2  * This File is part of Davix, The IO library for HTTP based protocols
3  * Copyright (C) CERN 2013
4  * Author: Adrien Devresse <adrien.devresse@cern.ch>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20 */
21 
22 #include <davix_internal.hpp>
23 
24 #include <neon/neonrequest.hpp>
25 #include <davix_context_internal.hpp>
26 #include <request/httprequest.hpp>
27 
28 namespace Davix {
29 
30 
31 
32 
33 /////////////////////////////////////////////////////////////////////////
34 /////////////////////////////////////////////////////////////////////////
35 
HttpRequest(NEONRequest * req)36 HttpRequest::HttpRequest(NEONRequest* req) {
37   std::cerr << "Usage of HttpRequest::HttpRequest(NEONRequest* req) is deprecated!" << std::endl;
38 }
39 
HttpRequest(Context & context,const Uri & uri,DavixError ** err)40 HttpRequest::HttpRequest(Context & context, const Uri & uri, DavixError** err) :
41     d_ptr(new NEONRequest(*this, context,uri)){
42 
43     DAVIX_SLOG(DAVIX_LOG_DEBUG, DAVIX_LOG_HTTP, "Create HttpRequest for {}", uri.getString());
44     if(uri.getStatus() != StatusCode::OK){
45         DavixError::setupError(err, davix_scope_http_request(), StatusCode::UriParsingError, fmt::format(" {} is not a valid HTTP or Webdav URL", uri));
46     }
47 }
48 
HttpRequest(Context & context,const std::string & url,DavixError ** err)49 HttpRequest::HttpRequest(Context & context, const std::string & url, DavixError** err) :
50     d_ptr(NULL){
51     Uri uri(url);
52     d_ptr= new NEONRequest(*this, context, uri);
53     if(uri.getStatus() != StatusCode::OK){
54         DavixError::setupError(err, davix_scope_http_request(), StatusCode::UriParsingError, fmt::format(" {} is not a valid HTTP or Webdav URL", uri));
55     }
56 }
57 
~HttpRequest()58 HttpRequest::~HttpRequest()
59 {
60     DAVIX_SLOG(DAVIX_LOG_DEBUG, DAVIX_LOG_CORE, "Destroy HttpRequest");
61     delete d_ptr;
62 }
63 
setRequestMethod(const std::string & request_str)64 void HttpRequest::setRequestMethod(const std::string &request_str){
65     d_ptr->setRequestMethod(request_str);
66 }
67 
68 
addHeaderField(const std::string & field,const std::string & value)69 void HttpRequest::addHeaderField(const std::string &field, const std::string &value){
70     d_ptr->addHeaderField(field, value);
71 }
72 
setParameters(const RequestParams & p)73 void HttpRequest::setParameters(const RequestParams &p){
74     d_ptr->setParameters(p);
75 }
76 
setRequestBody(const std::string & body)77 void HttpRequest::setRequestBody(const std::string &body){
78     d_ptr->setRequestBody(body);
79 }
80 
setRequestBody(const void * buffer,dav_size_t len_buff)81 void HttpRequest::setRequestBody(const void *buffer, dav_size_t len_buff){
82     d_ptr->setRequestBody(buffer, len_buff);
83 }
84 
setRequestBody(int fd,dav_off_t offset,dav_size_t len)85 void HttpRequest::setRequestBody(int fd, dav_off_t offset, dav_size_t len){
86     d_ptr->setRequestBody(fd, offset, len);
87 }
88 
setRequestBody(HttpBodyProvider provider,dav_size_t len,void * udata)89 void HttpRequest::setRequestBody(HttpBodyProvider provider, dav_size_t len, void* udata){
90     d_ptr->setRequestBody(provider, len, udata);
91 }
92 
getRequestCode()93 int HttpRequest::getRequestCode(){
94     return d_ptr->getRequestCode();
95 }
96 
executeRequest(DavixError ** err)97 int HttpRequest::executeRequest(DavixError **err){
98     TRY_DAVIX{
99         runPreRunHook();
100         return d_ptr->executeRequest(err);
101     }CATCH_DAVIX(err)
102     return -1;
103 }
104 
beginRequest(DavixError ** err)105 int HttpRequest::beginRequest(DavixError **err){
106     TRY_DAVIX{
107         // triggers Hooks
108         runPreRunHook();
109         return d_ptr->beginRequest(err);
110     }CATCH_DAVIX(err)
111     return -1;
112 }
113 
readBlock(char * buffer,dav_size_t max_size,DavixError ** err)114 dav_ssize_t HttpRequest::readBlock(char *buffer, dav_size_t max_size, DavixError **err){
115     TRY_DAVIX{
116         return d_ptr->readBlock(buffer, max_size, err);
117     }CATCH_DAVIX(err)
118     return -1;
119 }
120 
readBlock(std::vector<char> & buffer,dav_size_t max_size,DavixError ** err)121 dav_ssize_t HttpRequest::readBlock(std::vector<char> & buffer, dav_size_t max_size, DavixError **err){
122     dav_ssize_t ret=-1, v_size = (dav_ssize_t) buffer.size();
123     TRY_DAVIX{
124 
125         buffer.resize(v_size + max_size);
126         ret = readBlock(((char*) &buffer[0])+ v_size, max_size, err);
127         buffer.resize(v_size + ( (ret > 0)?ret:0));
128     }CATCH_DAVIX(err)
129     return ret;
130 }
131 
readSegment(char * buffer,dav_size_t max_size,DavixError ** err)132 dav_ssize_t HttpRequest::readSegment(char* buffer, dav_size_t max_size, DavixError** err){
133     return d_ptr->readSegment(buffer, max_size, false, err);
134 }
135 
readLine(char * buffer,dav_size_t max_size,DavixError ** err)136 dav_ssize_t HttpRequest::readLine(char *buffer, dav_size_t max_size, DavixError **err){
137     DAVIX_SLOG(DAVIX_LOG_DEBUG, DAVIX_LOG_CORE, "Davix::Request::readLine want to read a line of max {} chars", max_size);
138     dav_ssize_t ret= -1;
139     TRY_DAVIX{
140         if( (ret =  d_ptr->readLine(buffer, max_size, err)) >= 0){
141             DAVIX_SLOG(DAVIX_LOG_DEBUG, DAVIX_LOG_CORE, "Davix::Request::readLine got {} chars", ret);
142             DAVIX_SLOG(DAVIX_LOG_TRACE, DAVIX_LOG_CORE, "Davix::Request::readLine content\n[[{}]]\n", std::string(buffer, ret));
143         }
144     }CATCH_DAVIX(err)
145     return ret;
146 }
147 
discardBody(DavixError ** err)148 void HttpRequest::discardBody(DavixError** err){
149     char buffer[1024];
150     dav_ssize_t read;
151     TRY_DAVIX{
152         do {
153             read = d_ptr->readSegment(buffer, sizeof(buffer), false, err);
154         } while (read > 0 && *err == NULL);
155     }CATCH_DAVIX(err)
156 }
157 
readToFd(int fd,DavixError ** err)158 dav_ssize_t HttpRequest::readToFd(int fd, DavixError** err){
159     TRY_DAVIX{
160         return d_ptr->readToFd(fd, 0, err);
161     }CATCH_DAVIX(err)
162     return -1;
163 }
164 
165 
readToFd(int fd,dav_size_t read_size,DavixError ** err)166 dav_ssize_t HttpRequest::readToFd(int fd, dav_size_t read_size, DavixError** err){
167     TRY_DAVIX{
168         return d_ptr->readToFd(fd, read_size, err);
169     }CATCH_DAVIX(err)
170     return -1;
171 }
172 
endRequest(DavixError ** err)173 int HttpRequest::endRequest(DavixError **err){
174     TRY_DAVIX{
175         return d_ptr->endRequest(err);
176     }CATCH_DAVIX(err)
177     return -1;
178 }
179 
180 
clearAnswerContent()181 void HttpRequest::clearAnswerContent(){
182     d_ptr->clearAnswerContent();
183 }
184 
getAnswerHeader(const std::string & header_name,std::string & value) const185 bool HttpRequest::getAnswerHeader(const std::string &header_name, std::string &value) const{
186     return d_ptr->getAnswerHeader(header_name, value);
187 }
188 
getAnswerHeaders(HeaderVec & vec_headers) const189 size_t HttpRequest::getAnswerHeaders( HeaderVec & vec_headers) const{
190     return d_ptr->getAnswerHeaders(vec_headers);
191 }
192 
getAnswerContent()193 const char* HttpRequest::getAnswerContent(){
194     return d_ptr->getAnswerContent();
195 }
196 
getAnswerContentVec()197 std::vector<char> & HttpRequest::getAnswerContentVec(){
198     return d_ptr->getAnswerContentVec();
199 }
200 
201 
202 /// get content length
getAnswerSize() const203 dav_ssize_t HttpRequest::getAnswerSize() const{
204     return d_ptr->getAnswerSize();
205 }
206 
getLastModified() const207 time_t HttpRequest::getLastModified() const{
208     return d_ptr->getLastModified();
209 }
210 
211 
extractCacheToken() const212 HttpCacheToken* HttpRequest::extractCacheToken()const{
213     return NULL;
214 }
215 
useCacheToken(const HttpCacheToken * token)216 void HttpRequest::useCacheToken(const HttpCacheToken *token){
217     (void) token;
218 }
219 
220 /// set a HttpRequest flag
setFlag(const RequestFlag::RequestFlag flag,bool value)221 void HttpRequest::setFlag(const RequestFlag::RequestFlag flag, bool value){
222     d_ptr->setFlag(flag, value);
223 }
224 
225 /// get a HttpRequest flag value
getFlag(const RequestFlag::RequestFlag flag)226 bool HttpRequest::getFlag(const RequestFlag::RequestFlag flag){
227     return d_ptr->getFlag(flag);
228 }
229 
runPreRunHook()230 void HttpRequest::runPreRunHook(){
231     // triggers Hooks
232     RequestPreRunHook hook = d_ptr->getContext().getHook<RequestPreRunHook>();
233 
234     if(hook){
235         hook(d_ptr->getParameters(), *this, *(d_ptr->getOriginalUri()));
236     }
237 }
238 
239 
240 ///////////////////////////////////////////////////
241 ///// Simplified request GET
242 ////////////////////////////////////////////////////
243 
GetRequest(Context & context,const Uri & uri,DavixError ** err)244 GetRequest::GetRequest(Context & context, const Uri & uri, DavixError** err) :
245     HttpRequest(context, uri, err)
246 {
247 
248 }
249 
250 
251 ///////////////////////////////////////////////////
252 ///// Simplified request PUT
253 ////////////////////////////////////////////////////
254 
PutRequest(Context & context,const Uri & uri,DavixError ** err)255 PutRequest::PutRequest(Context & context, const Uri & uri, DavixError** err) :
256     HttpRequest(context, uri, err)
257 {
258     setRequestMethod("PUT");
259     setFlag(RequestFlag::SupportContinue100, true);
260     setFlag(RequestFlag::IdempotentRequest, false);
261 }
262 
263 ///////////////////////////////////////////////////
264 ///// Simplified request POST
265 ////////////////////////////////////////////////////
266 
PostRequest(Context & context,const Uri & uri,DavixError ** err)267 PostRequest::PostRequest(Context & context, const Uri & uri, DavixError** err) :
268     HttpRequest(context, uri, err)
269 {
270     setRequestMethod("POST");
271     setFlag(RequestFlag::IdempotentRequest, false);
272 }
273 
274 ///////////////////////////////////////////////////
275 ///// Simplified request HEAD
276 ////////////////////////////////////////////////////
277 
HeadRequest(Context & context,const Uri & uri,DavixError ** err)278 HeadRequest::HeadRequest(Context & context, const Uri & uri, DavixError** err) :
279     HttpRequest(context, uri, err)
280 {
281     setRequestMethod("HEAD");
282 }
283 
284 
285 ///////////////////////////////////////////////////
286 ///// Simplified request DELETE
287 ////////////////////////////////////////////////////
288 
DeleteRequest(Context & context,const Uri & uri,DavixError ** err)289 DeleteRequest::DeleteRequest(Context & context, const Uri & uri, DavixError** err) :
290     HttpRequest(context, uri, err)
291 {
292     setFlag(RequestFlag::IdempotentRequest, false);
293     setRequestMethod("DELETE");
294 }
295 
296 ///////////////////////////////////////////////////
297 ///// Simplified request PROPFIND
298 ////////////////////////////////////////////////////
299 
PropfindRequest(Context & context,const Uri & uri,DavixError ** err)300 PropfindRequest::PropfindRequest(Context & context, const Uri & uri, DavixError** err) :
301     HttpRequest(context, uri, err)
302 {
303     setRequestMethod("PROPFIND");
304 }
305 
306 
httpcodeToDavixError(int code,const std::string & scope,const std::string & end_message,StatusCode::Code & dav_code,std::string & err_msg)307 void httpcodeToDavixError(int code, const std::string &scope, const std::string & end_message, StatusCode::Code & dav_code, std::string & err_msg){
308     std::string str_msg = "Status Ok";
309     switch (code) {
310         case 200:           /* OK */
311         case 201:           /* Created */
312         case 202:           /* Accepted */
313         case 203:           /* Non-Authoritative Information */
314         case 204:           /* No Content */
315         case 206:           /* partial content*/
316         case 205:           /* Reset Content */
317         case 207:           /* Multi-Status */
318         case 304:           /* Not Modified */
319             dav_code = StatusCode::OK;
320             str_msg = "Success";
321             break;
322         case 401:           /* Unauthorized */
323         case 402:           /* Payment Required */
324         case 407:           /* Proxy Authentication Required */
325             dav_code = StatusCode::AuthentificationError;
326             str_msg = "Authentification Error";
327             break;
328         case 303:           /* See Other */
329         case 404:           /* Not Found */
330         case 410:           /* Gone */
331             dav_code = StatusCode::FileNotFound;
332             str_msg = "File not found";
333             break;
334         case 408:           /* Request Timeout */
335         case 504:           /* Gateway Timeout */
336             dav_code = StatusCode::OperationTimeout;
337             str_msg = "Operation timeout";
338             break;
339         case 409:
340             if (scope == davix_scope_mkdir_str()){
341                 dav_code = StatusCode::FileNotFound;
342                 str_msg = "Conflict, File not Found";
343             } else{
344                 dav_code = StatusCode::FileExist;
345                 str_msg = "Conflict, File Exist";
346             }
347             break;
348         case 423:           /* Locked */
349         case 403:           /* Forbidden */
350             dav_code = StatusCode::PermissionRefused;
351             str_msg = "Permission refused";
352             break;
353         break;
354         case 405:           /* Method Not Allowed */
355             if (scope == davix_scope_mkdir_str()){
356                 dav_code = StatusCode::FileExist;
357                 str_msg = "Method Not Allowed, File Exist";
358             } else{
359                 dav_code = StatusCode::PermissionRefused; // Technically is a EPERM
360                 str_msg = "Method Not Allowed, Permission refused";
361             }
362             break;
363         case 400:           /* Bad Request */
364         case 411:           /* Length Required */
365         case 412:           /* Precondition Failed */
366         case 414:           /* Request-URI Too Long */
367         case 415:           /* Unsupported Media Type */
368         case 424:           /* Failed Dependency */
369         case 501:           /* Not Implemented */
370         case 413:           /* Request Entity Too Large */
371             dav_code = StatusCode::ConnectionProblem;
372             str_msg = "Server Error";
373             break;
374         case 507:           /* Insufficient Storage */
375             dav_code = StatusCode::InsufficientStorage;
376             str_msg = "Insufficient Storage";
377             break;
378         case 301:           /* Moved Permanently */
379         case 300:           /* Multiple Choices */
380         case 302:           /* Found */
381             dav_code = StatusCode::RedirectionNeeded;
382             str_msg = "Redirection requested, transparent redirection disabled";
383             break;
384         case 305:           /* Use Proxy */
385         case 306:           /* (Unused) */
386         case 307:           /* Temporary Redirect */
387         case 406:           /* Not Acceptable */
388         case 416:           /* Requested Range Not Satisfiable */
389         case 417:           /* Expectation Failed */
390         case 422:           /* Unprocessable Entity */
391         case 500:           /* Internal Server Error */
392         case 502:           /* Bad Gateway */
393         case 503:           /* Service Unavailable */
394         case 505:           /* HTTP Version Not Supported */
395         default:
396             dav_code = StatusCode::UnknowError;
397             std::ostringstream ss;
398             ss << "Unexpected server error: " << code;
399             str_msg = ss.str().c_str();
400             break;
401     }
402 
403     err_msg.assign(fmt::format("HTTP {} : {} {}", code, str_msg, end_message));
404 }
405 
httpcodeToDavixError(int code,const std::string & scope,const std::string & end_message,DavixError ** err)406 void httpcodeToDavixError(int code, const std::string & scope, const std::string & end_message, DavixError** err){
407     StatusCode::Code davix_code;
408     std::string err_msg;
409     httpcodeToDavixError(code, scope, end_message, davix_code, err_msg);
410     DavixError::setupError(err, scope, davix_code, err_msg);
411 }
412 
413 
httpcodeToDavixException(int code,const std::string & scope,const std::string & end_message)414 void httpcodeToDavixException(int code, const std::string & scope, const std::string & end_message){
415     StatusCode::Code davix_code;
416     std::string err_msg;
417     httpcodeToDavixError(code, scope, end_message, davix_code, err_msg);
418     throw DavixException(scope, davix_code, err_msg);
419 }
420 
httpcodeIsValid(int code)421 bool httpcodeIsValid(int code)
422 {
423     switch (code) {
424         case 200:           /* OK */
425         case 201:           /* Created */
426         case 202:           /* Accepted */
427         case 203:           /* Non-Authoritative Information */
428         case 204:           /* No Content */
429         case 206:           /* partial content */
430         case 205:           /* Reset Content */
431         case 207:           /* Multi-Status */
432         case 304:           /* Not Modified */
433             return true;
434         default:
435             return false;
436     }
437 }
438 
439 
440 } // namespace Davix
441