|
Packit Service |
a2489d |
/*
|
|
Packit Service |
a2489d |
* lftp - file transfer program
|
|
Packit Service |
a2489d |
*
|
|
Packit Service |
a2489d |
* Copyright (c) 1996-2016 by Alexander V. Lukyanov (lav@yars.free.net)
|
|
Packit Service |
a2489d |
*
|
|
Packit Service |
a2489d |
* This program is free software; you can redistribute it and/or modify
|
|
Packit Service |
a2489d |
* it under the terms of the GNU General Public License as published by
|
|
Packit Service |
a2489d |
* the Free Software Foundation; either version 3 of the License, or
|
|
Packit Service |
a2489d |
* (at your option) any later version.
|
|
Packit Service |
a2489d |
*
|
|
Packit Service |
a2489d |
* This program is distributed in the hope that it will be useful,
|
|
Packit Service |
a2489d |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit Service |
a2489d |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit Service |
a2489d |
* GNU General Public License for more details.
|
|
Packit Service |
a2489d |
*
|
|
Packit Service |
a2489d |
* You should have received a copy of the GNU General Public License
|
|
Packit Service |
a2489d |
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
Packit Service |
a2489d |
*/
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
#include <config.h>
|
|
Packit Service |
a2489d |
#include "trio.h"
|
|
Packit Service |
a2489d |
#include <unistd.h>
|
|
Packit Service |
a2489d |
#include <sys/types.h>
|
|
Packit Service |
a2489d |
#include <sys/socket.h>
|
|
Packit Service |
a2489d |
#include <fcntl.h>
|
|
Packit Service |
a2489d |
#include <errno.h>
|
|
Packit Service |
a2489d |
#include <stdarg.h>
|
|
Packit Service |
a2489d |
#include <time.h>
|
|
Packit Service |
a2489d |
#include <fnmatch.h>
|
|
Packit Service |
a2489d |
#include <locale.h>
|
|
Packit Service |
a2489d |
#include <assert.h>
|
|
Packit Service |
a2489d |
#include "Http.h"
|
|
Packit Service |
a2489d |
#include "ResMgr.h"
|
|
Packit Service |
a2489d |
#include "log.h"
|
|
Packit Service |
a2489d |
#include "url.h"
|
|
Packit Service |
a2489d |
#include "HttpAuth.h"
|
|
Packit Service |
a2489d |
#include "HttpDir.h"
|
|
Packit Service |
a2489d |
#include "misc.h"
|
|
Packit Service |
a2489d |
#include "buffer_ssl.h"
|
|
Packit Service |
a2489d |
#include "buffer_zlib.h"
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
#include "ascii_ctype.h"
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
#if !HAVE_DECL_STRPTIME
|
|
Packit Service |
a2489d |
CDECL char *strptime(const char *buf, const char *format, struct tm *tm);
|
|
Packit Service |
a2489d |
#endif
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
#define super NetAccess
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
#define max_buf 0x10000
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
#define HTTP_DEFAULT_PORT "80"
|
|
Packit Service |
a2489d |
#define HTTP_DEFAULT_PROXY_PORT "3128"
|
|
Packit Service |
a2489d |
#define HTTPS_DEFAULT_PORT "443"
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
enum {
|
|
Packit Service |
a2489d |
H_Continue=100,
|
|
Packit Service |
a2489d |
H_Switching_Protocols=101,
|
|
Packit Service |
a2489d |
H_Processing=102,
|
|
Packit Service |
a2489d |
H_Ok=200,
|
|
Packit Service |
a2489d |
H_Created=201,
|
|
Packit Service |
a2489d |
H_Accepted=202,
|
|
Packit Service |
a2489d |
H_Non_Authoritative_Information=203,
|
|
Packit Service |
a2489d |
H_No_Content=204,
|
|
Packit Service |
a2489d |
H_Reset_Content=205,
|
|
Packit Service |
a2489d |
H_Partial_Content=206,
|
|
Packit Service |
a2489d |
H_Multi_Status=207,
|
|
Packit Service |
a2489d |
H_Moved_Permanently=301,
|
|
Packit Service |
a2489d |
H_Found=302,
|
|
Packit Service |
a2489d |
H_See_Other=303,
|
|
Packit Service |
a2489d |
H_Not_Modified=304,
|
|
Packit Service |
a2489d |
H_Use_Proxy=305,
|
|
Packit Service |
a2489d |
H_Temporary_Redirect=307,
|
|
Packit Service |
a2489d |
H_Bad_Request=400,
|
|
Packit Service |
a2489d |
H_Unauthorized=401,
|
|
Packit Service |
a2489d |
H_Payment_Required=402,
|
|
Packit Service |
a2489d |
H_Forbidden=403,
|
|
Packit Service |
a2489d |
H_Not_Found=404,
|
|
Packit Service |
a2489d |
H_Method_Not_Allowed=405,
|
|
Packit Service |
a2489d |
H_Not_Acceptable=406,
|
|
Packit Service |
a2489d |
H_Proxy_Authentication_Required=407,
|
|
Packit Service |
a2489d |
H_Request_Timeout=408,
|
|
Packit Service |
a2489d |
H_Conflict=409,
|
|
Packit Service |
a2489d |
H_Gone=410,
|
|
Packit Service |
a2489d |
H_Length_Required=411,
|
|
Packit Service |
a2489d |
H_Precondition_Failed=412,
|
|
Packit Service |
a2489d |
H_Request_Entity_Too_Large=413,
|
|
Packit Service |
a2489d |
H_Request_URI_Too_Long=414,
|
|
Packit Service |
a2489d |
H_Unsupported_Media_Type=415,
|
|
Packit Service |
a2489d |
H_Requested_Range_Not_Satisfiable=416,
|
|
Packit Service |
a2489d |
H_Expectation_Failed=417,
|
|
Packit Service |
a2489d |
H_Unprocessable_Entity=422,
|
|
Packit Service |
a2489d |
H_Locked=423,
|
|
Packit Service |
a2489d |
H_Failed_Dependency=424,
|
|
Packit Service |
a2489d |
H_Too_Many_Requests=429,
|
|
Packit Service |
a2489d |
H_Internal_Server_Error=500,
|
|
Packit Service |
a2489d |
H_Not_Implemented=501,
|
|
Packit Service |
a2489d |
H_Bad_Gateway=502,
|
|
Packit Service |
a2489d |
H_Service_Unavailable=503,
|
|
Packit Service |
a2489d |
H_Gateway_Timeout=504,
|
|
Packit Service |
a2489d |
H_HTTP_Version_Not_Supported=505,
|
|
Packit Service |
a2489d |
H_Insufficient_Storage=507,
|
|
Packit Service |
a2489d |
};
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
/* Some status code validation macros: */
|
|
Packit Service |
a2489d |
#define H_2XX(x) (((x) >= 200) && ((x) <= 299))
|
|
Packit Service |
a2489d |
#define H_5XX(x) (((x) >= 500) && ((x) <= 599))
|
|
Packit Service |
a2489d |
#define H_PARTIAL(x) ((x) == H_Partial_Content)
|
|
Packit Service |
a2489d |
#define H_REDIRECTED(x) (((x) == H_Moved_Permanently) || ((x) == H_Found) || ((x) == H_See_Other) || ((x) == H_Temporary_Redirect))
|
|
Packit Service |
a2489d |
#define H_EMPTY(x) (((x) == H_No_Content) || ((x) == H_Reset_Content))
|
|
Packit Service |
a2489d |
#define H_CONTINUE(x) ((x) == H_Continue || (x) == H_Processing)
|
|
Packit Service |
a2489d |
#define H_REQUESTED_RANGE_NOT_SATISFIABLE(x) ((x) == H_Requested_Range_Not_Satisfiable)
|
|
Packit Service |
a2489d |
#define H_TRANSIENT(x) ((x)==H_Request_Timeout || (x)==H_Bad_Gateway || (x)==H_Service_Unavailable || (x)==H_Gateway_Timeout)
|
|
Packit Service |
a2489d |
#define H_UNSUPPORTED(x) ((x)==H_Bad_Request || (x)==H_Not_Implemented)
|
|
Packit Service |
a2489d |
#define H_AUTH_REQ(x) ((x)==H_Unauthorized || (x)==H_Proxy_Authentication_Required)
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
#ifndef EINPROGRESS
|
|
Packit Service |
a2489d |
#define EINPROGRESS -1
|
|
Packit Service |
a2489d |
#endif
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
enum { CHUNK_SIZE_UNKNOWN=-1 };
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
Http::Connection::Connection(int s,const char *c)
|
|
Packit Service |
a2489d |
: closure(c), sock(s)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
Http::Connection::~Connection()
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
close(sock);
|
|
Packit Service |
a2489d |
/* make sure we free buffers before ssl */
|
|
Packit Service |
a2489d |
recv_buf=0;
|
|
Packit Service |
a2489d |
send_buf=0;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
void Http::Connection::MakeBuffers()
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
send_buf=new IOBufferFDStream(
|
|
Packit Service |
a2489d |
new FDStream(sock,"<output-socket>"),IOBuffer::PUT);
|
|
Packit Service |
a2489d |
recv_buf=new IOBufferFDStream(
|
|
Packit Service |
a2489d |
new FDStream(sock,"<input-socket>"),IOBuffer::GET);
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
void Http::Init()
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
state=DISCONNECTED;
|
|
Packit Service |
a2489d |
tunnel_state=NO_TUNNEL;
|
|
Packit Service |
a2489d |
body_size=-1;
|
|
Packit Service |
a2489d |
bytes_received=0;
|
|
Packit Service |
a2489d |
status_code=0;
|
|
Packit Service |
a2489d |
status_consumed=0;
|
|
Packit Service |
a2489d |
proto_version=0x10;
|
|
Packit Service |
a2489d |
sent_eot=false;
|
|
Packit Service |
a2489d |
last_method=0;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
default_cwd="/";
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
keep_alive=false;
|
|
Packit Service |
a2489d |
keep_alive_max=-1;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
array_send=0;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
chunked=false;
|
|
Packit Service |
a2489d |
chunked_trailer=false;
|
|
Packit Service |
a2489d |
chunk_size=CHUNK_SIZE_UNKNOWN;
|
|
Packit Service |
a2489d |
chunk_pos=0;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
request_pos=0;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
no_ranges=false;
|
|
Packit Service |
a2489d |
seen_ranges_bytes=false;
|
|
Packit Service |
a2489d |
entity_date_set=false;
|
|
Packit Service |
a2489d |
sending_proppatch=false;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
no_cache_this=false;
|
|
Packit Service |
a2489d |
no_cache=false;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
auth_sent[0]=auth_sent[1]=0;
|
|
Packit Service |
a2489d |
auth_scheme[0]=auth_scheme[1]=HttpAuth::NONE;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
use_propfind_now=true;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
retry_after=0;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
hftp=false;
|
|
Packit Service |
a2489d |
https=false;
|
|
Packit Service |
a2489d |
use_head=true;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
user_agent=0;
|
|
Packit Service |
a2489d |
special=HTTP_NONE;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
Http::Http() : super()
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
Init();
|
|
Packit Service |
a2489d |
Reconfig();
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
Http::Http(const Http *f) : super(f)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
Init();
|
|
Packit Service |
a2489d |
Reconfig();
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
Http::~Http()
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
Close();
|
|
Packit Service |
a2489d |
Disconnect();
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
void Http::MoveConnectionHere(Http *o)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
conn=o->conn.borrow();
|
|
Packit Service |
a2489d |
conn->ResumeInternal();
|
|
Packit Service |
a2489d |
rate_limit=o->rate_limit.borrow();
|
|
Packit Service |
a2489d |
last_method=o->last_method; o->last_method=0;
|
|
Packit Service |
a2489d |
last_uri.move_here(o->last_uri);
|
|
Packit Service |
a2489d |
last_url.move_here(o->last_url);
|
|
Packit Service |
a2489d |
timeout_timer.Reset(o->timeout_timer);
|
|
Packit Service |
a2489d |
state=CONNECTED;
|
|
Packit Service |
a2489d |
tunnel_state=o->tunnel_state;
|
|
Packit Service |
a2489d |
o->Disconnect();
|
|
Packit Service |
a2489d |
ResumeInternal();
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
void Http::DisconnectLL()
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
Enter(this);
|
|
Packit Service |
a2489d |
rate_limit=0;
|
|
Packit Service |
a2489d |
if(conn)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
LogNote(7,_("Closing HTTP connection"));
|
|
Packit Service |
a2489d |
conn=0;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
if(!Error() && !H_AUTH_REQ(status_code))
|
|
Packit Service |
a2489d |
auth_sent[0]=auth_sent[1]=0;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
if(state!=DONE && (real_pos>0 || special==HTTP_POST)
|
|
Packit Service |
a2489d |
&& !Error() && !H_AUTH_REQ(status_code)) {
|
|
Packit Service |
a2489d |
if(last_method && !strcmp(last_method,"POST"))
|
|
Packit Service |
a2489d |
SetError(FATAL,_("POST method failed"));
|
|
Packit Service |
a2489d |
else if(ModeIs(STORE))
|
|
Packit Service |
a2489d |
SetError(STORE_FAILED,0);
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
if(ModeIs(STORE) && H_AUTH_REQ(status_code))
|
|
Packit Service |
a2489d |
pos=real_pos=request_pos; // resend all the data again
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
last_method=0;
|
|
Packit Service |
a2489d |
last_uri.unset();
|
|
Packit Service |
a2489d |
last_url.unset();
|
|
Packit Service |
a2489d |
ResetRequestData();
|
|
Packit Service |
a2489d |
state=DISCONNECTED;
|
|
Packit Service |
a2489d |
Leave(this);
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
void Http::ResetRequestData()
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
body_size=-1;
|
|
Packit Service |
a2489d |
bytes_received=0;
|
|
Packit Service |
a2489d |
real_pos=no_ranges?0:-1;
|
|
Packit Service |
a2489d |
status.set(0);
|
|
Packit Service |
a2489d |
status_consumed=0;
|
|
Packit Service |
a2489d |
line.set(0);
|
|
Packit Service |
a2489d |
sent_eot=false;
|
|
Packit Service |
a2489d |
keep_alive=false;
|
|
Packit Service |
a2489d |
keep_alive_max=-1;
|
|
Packit Service |
a2489d |
array_send=fileset_for_info?fileset_for_info->curr_index():0;
|
|
Packit Service |
a2489d |
chunked=false;
|
|
Packit Service |
a2489d |
chunked_trailer=false;
|
|
Packit Service |
a2489d |
chunk_size=CHUNK_SIZE_UNKNOWN;
|
|
Packit Service |
a2489d |
chunk_pos=0;
|
|
Packit Service |
a2489d |
request_pos=0;
|
|
Packit Service |
a2489d |
propfind=0;
|
|
Packit Service |
a2489d |
inflate=0;
|
|
Packit Service |
a2489d |
seen_ranges_bytes=false;
|
|
Packit Service |
a2489d |
entity_date_set=false;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
void Http::Close()
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
if(mode==CLOSED)
|
|
Packit Service |
a2489d |
return;
|
|
Packit Service |
a2489d |
if(conn && conn->recv_buf)
|
|
Packit Service |
a2489d |
conn->recv_buf->Roll(); // try to read any remaining data
|
|
Packit Service |
a2489d |
if(conn && keep_alive && (keep_alive_max>0 || keep_alive_max==-1)
|
|
Packit Service |
a2489d |
&& !ModeIs(STORE) && !conn->recv_buf->Eof() && (state==RECEIVING_BODY || state==DONE))
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
conn->recv_buf->Resume();
|
|
Packit Service |
a2489d |
conn->recv_buf->Roll();
|
|
Packit Service |
a2489d |
if(xstrcmp(last_method,"HEAD"))
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
// check if all data are in buffer
|
|
Packit Service |
a2489d |
if(!chunked) // chunked is a bit complex, so don't handle it
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
bytes_received+=conn->recv_buf->Size();
|
|
Packit Service |
a2489d |
conn->recv_buf->Skip(conn->recv_buf->Size());
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
if(!(body_size>=0 && bytes_received==body_size))
|
|
Packit Service |
a2489d |
goto disconnect;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
// can reuse the connection.
|
|
Packit Service |
a2489d |
state=CONNECTED;
|
|
Packit Service |
a2489d |
ResetRequestData();
|
|
Packit Service |
a2489d |
rate_limit=0;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
else
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
disconnect:
|
|
Packit Service |
a2489d |
Disconnect();
|
|
Packit Service |
a2489d |
DontSleep();
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
array_send=0;
|
|
Packit Service |
a2489d |
no_cache_this=false;
|
|
Packit Service |
a2489d |
auth_sent[0]=auth_sent[1]=0;
|
|
Packit Service |
a2489d |
auth_scheme[0]=auth_scheme[1]=HttpAuth::NONE;
|
|
Packit Service |
a2489d |
no_ranges=!QueryBool("use-range",hostname);
|
|
Packit Service |
a2489d |
use_propfind_now=QueryBool("use-propfind",hostname);
|
|
Packit Service |
a2489d |
special=HTTP_NONE;
|
|
Packit Service |
a2489d |
special_data.set(0);
|
|
Packit Service |
a2489d |
sending_proppatch=false;
|
|
Packit Service |
a2489d |
super::Close();
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
void Http::Send(const xstring& str)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
if(str.length()==0)
|
|
Packit Service |
a2489d |
return;
|
|
Packit Service |
a2489d |
LogSend(5,str);
|
|
Packit Service |
a2489d |
conn->send_buf->Put(str);
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
void Http::Send(const char *format,...)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
va_list va;
|
|
Packit Service |
a2489d |
va_start(va,format);
|
|
Packit Service |
a2489d |
xstring& str=xstring::vformat(format,va);
|
|
Packit Service |
a2489d |
va_end(va);
|
|
Packit Service |
a2489d |
Send(str);
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
void Http::Send(const HttpHeader *hdr)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
Send("%s: %s\r\n",hdr->GetName(),hdr->GetValue());
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
void Http::AppendHostEncoded(xstring& buf,const char *host)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
if(is_ipv6_address(host))
|
|
Packit Service |
a2489d |
buf.append('[').append(host).append(']');
|
|
Packit Service |
a2489d |
else
|
|
Packit Service |
a2489d |
buf.append_url_encoded(host,URL_HOST_UNSAFE);
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
void Http::SendMethod(const char *method,const char *efile)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
xstring& stripped_hostname=xstring::get_tmp(hostname);
|
|
Packit Service |
a2489d |
stripped_hostname.truncate_at('%');
|
|
Packit Service |
a2489d |
xstring ehost;
|
|
Packit Service |
a2489d |
AppendHostEncoded(ehost,xidna_to_ascii(stripped_hostname));
|
|
Packit Service |
a2489d |
if(portname) {
|
|
Packit Service |
a2489d |
ehost.append(':');
|
|
Packit Service |
a2489d |
ehost.append(url::encode(portname,URL_PORT_UNSAFE));
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
if(!use_head && !strcmp(method,"HEAD"))
|
|
Packit Service |
a2489d |
method="GET";
|
|
Packit Service |
a2489d |
last_method=method;
|
|
Packit Service |
a2489d |
if(file_url)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
efile=file_url;
|
|
Packit Service |
a2489d |
if(!proxy)
|
|
Packit Service |
a2489d |
efile+=url::path_index(efile);
|
|
Packit Service |
a2489d |
else if(!strncmp(efile,"hftp://",7))
|
|
Packit Service |
a2489d |
efile++;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
if(hftp && mode!=LONG_LIST && mode!=CHANGE_DIR && mode!=MAKE_DIR
|
|
Packit Service |
a2489d |
&& mode!=REMOVE && mode!=REMOVE_DIR
|
|
Packit Service |
a2489d |
&& (strlen(efile)<7 || strncmp(efile+strlen(efile)-7,";type=",6))
|
|
Packit Service |
a2489d |
&& QueryBool("use-type",hostname))
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
efile=xstring::format("%s;type=%c",efile,ascii?'a':'i');
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
/*
|
|
Packit Service |
a2489d |
Handle the case when the user has not given us
|
|
Packit Service |
a2489d |
get http://foobar.org (note the absense of the trailing /
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
It fixes segfault with a certain webserver which I've
|
|
Packit Service |
a2489d |
seen ... (Geoffrey Lee <glee@gnupilgrims.org>).
|
|
Packit Service |
a2489d |
*/
|
|
Packit Service |
a2489d |
if(*efile=='\0')
|
|
Packit Service |
a2489d |
efile="/";
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
last_uri.set(efile+(proxy?url::path_index(efile):0));
|
|
Packit Service |
a2489d |
if(last_uri.length()==0)
|
|
Packit Service |
a2489d |
last_uri.set("/");
|
|
Packit Service |
a2489d |
if(proxy)
|
|
Packit Service |
a2489d |
last_url.set(efile);
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
Send("%s %s HTTP/1.1\r\n",method,efile);
|
|
Packit Service |
a2489d |
Send("Host: %s\r\n",ehost.get());
|
|
Packit Service |
a2489d |
if(user_agent && user_agent[0])
|
|
Packit Service |
a2489d |
Send("User-Agent: %s\r\n",user_agent);
|
|
Packit Service |
a2489d |
if(!hftp)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
const char *content_type=0;
|
|
Packit Service |
a2489d |
if(!strcmp(method,"PUT"))
|
|
Packit Service |
a2489d |
content_type=Query("put-content-type",hostname);
|
|
Packit Service |
a2489d |
else if(!strcmp(method,"POST"))
|
|
Packit Service |
a2489d |
content_type=Query("post-content-type",hostname);
|
|
Packit Service |
a2489d |
if(content_type && content_type[0])
|
|
Packit Service |
a2489d |
Send("Content-Type: %s\r\n",content_type);
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
const char *accept=Query("accept",hostname);
|
|
Packit Service |
a2489d |
if(accept && accept[0])
|
|
Packit Service |
a2489d |
Send("Accept: %s\r\n",accept);
|
|
Packit Service |
a2489d |
accept=Query("accept-language",hostname);
|
|
Packit Service |
a2489d |
if(accept && accept[0])
|
|
Packit Service |
a2489d |
Send("Accept-Language: %s\r\n",accept);
|
|
Packit Service |
a2489d |
accept=Query("accept-charset",hostname);
|
|
Packit Service |
a2489d |
if(accept && accept[0])
|
|
Packit Service |
a2489d |
Send("Accept-Charset: %s\r\n",accept);
|
|
Packit Service |
a2489d |
accept=Query("accept-encoding",hostname);
|
|
Packit Service |
a2489d |
if(accept && accept[0])
|
|
Packit Service |
a2489d |
Send("Accept-Encoding: %s\r\n",accept);
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
const char *referer=Query("referer",hostname);
|
|
Packit Service |
a2489d |
const char *slash="";
|
|
Packit Service |
a2489d |
if(!xstrcmp(referer,"."))
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
referer=GetConnectURL(NO_USER+NO_PASSWORD);
|
|
Packit Service |
a2489d |
if(last_char(referer)!='/' && !cwd.is_file)
|
|
Packit Service |
a2489d |
slash="/";
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
if(referer && referer[0])
|
|
Packit Service |
a2489d |
Send("Referer: %s%s\r\n",referer,slash);
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
xstring cookie;
|
|
Packit Service |
a2489d |
MakeCookie(cookie,hostname,efile+(proxy?url::path_index(efile):0));
|
|
Packit Service |
a2489d |
if(cookie.length()>0)
|
|
Packit Service |
a2489d |
Send("Cookie: %s\r\n",cookie.get());
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
void Http::SendBasicAuth(const char *tag,const char *auth)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
if(!auth || !*auth)
|
|
Packit Service |
a2489d |
return;
|
|
Packit Service |
a2489d |
int auth_len=strlen(auth);
|
|
Packit Service |
a2489d |
char *buf64=string_alloca(base64_length(auth_len)+1);
|
|
Packit Service |
a2489d |
base64_encode(auth,buf64,auth_len);
|
|
Packit Service |
a2489d |
Send("%s: Basic %s\r\n",tag,buf64);
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
void Http::SendBasicAuth(const char *tag,const char *user,const char *pass)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
/* Basic scheme */
|
|
Packit Service |
a2489d |
SendBasicAuth(tag,xstring::cat(user,":",pass,NULL));
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
void Http::SendAuth(HttpAuth::target_t target,const char *user,const char *uri)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
auth_scheme[target]=HttpAuth::NONE;
|
|
Packit Service |
a2489d |
if(!user)
|
|
Packit Service |
a2489d |
return;
|
|
Packit Service |
a2489d |
HttpAuth *auth=HttpAuth::Get(target,GetFileURL(file,NO_USER),user);
|
|
Packit Service |
a2489d |
if(auth && auth->Update(last_method,uri)) {
|
|
Packit Service |
a2489d |
auth_sent[target]++;
|
|
Packit Service |
a2489d |
Send(auth->GetHeader());
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
void Http::SendProxyAuth()
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
SendAuth(HttpAuth::PROXY,proxy_user,last_url);
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
void Http::SendAuth()
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
if(hftp && !auth_scheme[HttpAuth::WWW] && user && pass && QueryBool("use-authorization",proxy)) {
|
|
Packit Service |
a2489d |
SendBasicAuth("Authorization",user,pass);
|
|
Packit Service |
a2489d |
return;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
SendAuth(HttpAuth::WWW,user?user:auth_user,last_uri);
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
void Http::SendCacheControl()
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
const char *cc_setting=Query("cache-control",hostname);
|
|
Packit Service |
a2489d |
const char *cc_no_cache=(no_cache || no_cache_this)?"no-cache":0;
|
|
Packit Service |
a2489d |
if(!*cc_setting)
|
|
Packit Service |
a2489d |
cc_setting=0;
|
|
Packit Service |
a2489d |
if(!cc_setting && !cc_no_cache)
|
|
Packit Service |
a2489d |
return;
|
|
Packit Service |
a2489d |
int cc_no_cache_len=xstrlen(cc_no_cache);
|
|
Packit Service |
a2489d |
if(cc_no_cache && cc_setting)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
const char *pos=strstr(cc_setting,cc_no_cache);
|
|
Packit Service |
a2489d |
if(pos && (pos==cc_setting || pos[-1]==' ')
|
|
Packit Service |
a2489d |
&& (pos[cc_no_cache_len]==0 || pos[cc_no_cache_len]==' '))
|
|
Packit Service |
a2489d |
cc_no_cache=0, cc_no_cache_len=0;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
xstring& cc=xstring::join(",",2,cc_no_cache,cc_setting);
|
|
Packit Service |
a2489d |
if(*cc)
|
|
Packit Service |
a2489d |
Send("Cache-Control: %s\r\n",cc.get());
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
bool Http::ModeSupported()
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
switch((open_mode)mode)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
case CLOSED:
|
|
Packit Service |
a2489d |
case QUOTE_CMD:
|
|
Packit Service |
a2489d |
case LIST:
|
|
Packit Service |
a2489d |
case CHANGE_MODE:
|
|
Packit Service |
a2489d |
case LINK:
|
|
Packit Service |
a2489d |
case SYMLINK:
|
|
Packit Service |
a2489d |
return false;
|
|
Packit Service |
a2489d |
case CONNECT_VERIFY:
|
|
Packit Service |
a2489d |
case RETRIEVE:
|
|
Packit Service |
a2489d |
case STORE:
|
|
Packit Service |
a2489d |
case MAKE_DIR:
|
|
Packit Service |
a2489d |
case CHANGE_DIR:
|
|
Packit Service |
a2489d |
case ARRAY_INFO:
|
|
Packit Service |
a2489d |
case REMOVE_DIR:
|
|
Packit Service |
a2489d |
case REMOVE:
|
|
Packit Service |
a2489d |
case LONG_LIST:
|
|
Packit Service |
a2489d |
case RENAME:
|
|
Packit Service |
a2489d |
return true;
|
|
Packit Service |
a2489d |
case MP_LIST:
|
|
Packit Service |
a2489d |
#if USE_EXPAT
|
|
Packit Service |
a2489d |
return QueryBool("use-propfind",hostname);
|
|
Packit Service |
a2489d |
#else
|
|
Packit Service |
a2489d |
// without XML parser it is meaningless to retrieve XML file info.
|
|
Packit Service |
a2489d |
return false;
|
|
Packit Service |
a2489d |
#endif
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
abort(); // should not happen
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
void Http::DirFile(xstring& path,const xstring& ecwd,const xstring& efile) const
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
const int base=path.length();
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
if(efile[0]=='/') {
|
|
Packit Service |
a2489d |
path.append(efile);
|
|
Packit Service |
a2489d |
} else if(efile[0]=='~' || ecwd.length()==0 || (ecwd.eq("~") && !hftp)) {
|
|
Packit Service |
a2489d |
path.append('/');
|
|
Packit Service |
a2489d |
path.append(efile);
|
|
Packit Service |
a2489d |
} else {
|
|
Packit Service |
a2489d |
size_t min_len=path.length()+1;
|
|
Packit Service |
a2489d |
if(ecwd[0]!='/')
|
|
Packit Service |
a2489d |
path.append('/');
|
|
Packit Service |
a2489d |
path.append(ecwd);
|
|
Packit Service |
a2489d |
if(ecwd.last_char()!='/' && efile.length()>0)
|
|
Packit Service |
a2489d |
path.append('/');
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
// reduce . and .. at beginning of efile:
|
|
Packit Service |
a2489d |
// * get the minimum path length (so that we don't remove ~user)
|
|
Packit Service |
a2489d |
// * skip .; handle .. using basename_ptr to chomp the path.
|
|
Packit Service |
a2489d |
if(path[min_len]=='~') {
|
|
Packit Service |
a2489d |
while(path[min_len] && path[min_len]!='/')
|
|
Packit Service |
a2489d |
++min_len;
|
|
Packit Service |
a2489d |
if(path[min_len]=='/')
|
|
Packit Service |
a2489d |
++min_len;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
const char *e=efile;
|
|
Packit Service |
a2489d |
while(e[0]=='.') {
|
|
Packit Service |
a2489d |
if(e[1]=='/' || e[1]==0)
|
|
Packit Service |
a2489d |
++e;
|
|
Packit Service |
a2489d |
else if(e[1]=='.' && (e[2]=='/' || e[2]==0)) {
|
|
Packit Service |
a2489d |
if(path.length()<=min_len)
|
|
Packit Service |
a2489d |
break;
|
|
Packit Service |
a2489d |
const char *bn=basename_ptr(path+min_len);
|
|
Packit Service |
a2489d |
path.truncate(bn-path);
|
|
Packit Service |
a2489d |
e+=2;
|
|
Packit Service |
a2489d |
} else
|
|
Packit Service |
a2489d |
break;
|
|
Packit Service |
a2489d |
if(*e=='/')
|
|
Packit Service |
a2489d |
++e;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
path.append(e);
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
// remove "/~" or "/~/"
|
|
Packit Service |
a2489d |
if(path[base+1]=='~' && path[base+2]==0)
|
|
Packit Service |
a2489d |
path.truncate(base+1);
|
|
Packit Service |
a2489d |
else if(path[base+1]=='~' && path[base+2]=='/')
|
|
Packit Service |
a2489d |
path.set_substr(base,2,"");
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
void Http::SendPropfind(const xstring& efile,int depth)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
SendMethod("PROPFIND",efile);
|
|
Packit Service |
a2489d |
Send("Depth: %d\r\n",depth);
|
|
Packit Service |
a2489d |
if(allprop.length()>0)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
Send("Content-Type: text/xml\r\n");
|
|
Packit Service |
a2489d |
Send("Content-Length: %d\r\n",int(allprop.length()));
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
void Http::SendPropfindBody()
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
Send(allprop);
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
const xstring& Http::FormatLastModified(time_t lm)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
static const char weekday_names[][4]={
|
|
Packit Service |
a2489d |
"Sun","Mon","Tue","Wed","Thu","Fri","Sat"
|
|
Packit Service |
a2489d |
};
|
|
Packit Service |
a2489d |
const struct tm *t=gmtime(&lm);
|
|
Packit Service |
a2489d |
return xstring::format("%s, %2d %s %04d %02d:%02d:%02d GMT",
|
|
Packit Service |
a2489d |
weekday_names[t->tm_wday],t->tm_mday,month_names[t->tm_mon],
|
|
Packit Service |
a2489d |
t->tm_year+1900,t->tm_hour,t->tm_min,t->tm_sec);
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
void Http::SendProppatch(const xstring& efile)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
SendMethod("PROPPATCH",efile);
|
|
Packit Service |
a2489d |
xstring prop(
|
|
Packit Service |
a2489d |
""
|
|
Packit Service |
a2489d |
"<propertyupdate xmlns=\"DAV:\">"
|
|
Packit Service |
a2489d |
"<set>"
|
|
Packit Service |
a2489d |
"<prop>"
|
|
Packit Service |
a2489d |
"<getlastmodified>");
|
|
Packit Service |
a2489d |
prop.append(FormatLastModified(entity_date)).append(
|
|
Packit Service |
a2489d |
"</getlastmodified>"
|
|
Packit Service |
a2489d |
"</prop>"
|
|
Packit Service |
a2489d |
"</set>"
|
|
Packit Service |
a2489d |
"</propertyupdate>");
|
|
Packit Service |
a2489d |
Send("Content-Type: text/xml\r\n");
|
|
Packit Service |
a2489d |
Send("Content-Length: %d\r\n",int(prop.length()));
|
|
Packit Service |
a2489d |
Send("\r\n");
|
|
Packit Service |
a2489d |
Send(prop);
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
void Http::SendRequest(const char *connection,const char *f)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
xstring efile;
|
|
Packit Service |
a2489d |
xstring ecwd;
|
|
Packit Service |
a2489d |
bool add_slash=true;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
if(mode==CHANGE_DIR && new_cwd && new_cwd->url)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
const char *efile_c=new_cwd->url+url::path_index(new_cwd->url);
|
|
Packit Service |
a2489d |
if(!*efile_c)
|
|
Packit Service |
a2489d |
efile_c="/";
|
|
Packit Service |
a2489d |
efile.set(efile_c);
|
|
Packit Service |
a2489d |
add_slash=false;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
else
|
|
Packit Service |
a2489d |
efile.set(url::encode(f,URL_PATH_UNSAFE));
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
if(cwd.url)
|
|
Packit Service |
a2489d |
ecwd.set(cwd.url+url::path_index(cwd.url));
|
|
Packit Service |
a2489d |
else
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
ecwd.set(url::encode(cwd,URL_PATH_UNSAFE));
|
|
Packit Service |
a2489d |
if(hftp && ecwd[0]=='/' && ecwd[1]!='~')
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
// root directory in ftp urls needs special encoding. (/%2Fpath)
|
|
Packit Service |
a2489d |
ecwd.set_substr(1,0,"%2F");
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
if(cwd.is_file)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
if(efile[0])
|
|
Packit Service |
a2489d |
ecwd.truncate(basename_ptr(ecwd+(!strncmp(ecwd,"/~",2)))-ecwd);
|
|
Packit Service |
a2489d |
add_slash=false;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
if(mode==CHANGE_DIR && new_cwd && !new_cwd->url)
|
|
Packit Service |
a2489d |
add_slash=!new_cwd->is_file;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
xstring pfile;
|
|
Packit Service |
a2489d |
if(proxy && !https)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
const char *proto="http";
|
|
Packit Service |
a2489d |
if(hftp)
|
|
Packit Service |
a2489d |
proto="ftp";
|
|
Packit Service |
a2489d |
pfile.vset(proto,"://",NULL);
|
|
Packit Service |
a2489d |
if(hftp && user && pass)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
pfile.append(url::encode(user,URL_USER_UNSAFE));
|
|
Packit Service |
a2489d |
if(!QueryBool("use-authorization",proxy))
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
pfile.append(':');
|
|
Packit Service |
a2489d |
pfile.append(url::encode(pass,URL_PASS_UNSAFE));
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
pfile.append('@');
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
AppendHostEncoded(pfile,hostname);
|
|
Packit Service |
a2489d |
if(portname)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
pfile.append(':');
|
|
Packit Service |
a2489d |
pfile.append(url::encode(portname,URL_PORT_UNSAFE));
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
else
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
pfile.set("");
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
DirFile(pfile,ecwd,efile);
|
|
Packit Service |
a2489d |
efile.set(pfile);
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
if(pos==0)
|
|
Packit Service |
a2489d |
real_pos=0;
|
|
Packit Service |
a2489d |
if(ModeIs(STORE)) // can't seek before writing
|
|
Packit Service |
a2489d |
real_pos=pos;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
#ifdef DEBUG_MP_LIST
|
|
Packit Service |
a2489d |
if(mode==RETRIEVE && file[0]==0)
|
|
Packit Service |
a2489d |
mode=MP_LIST;
|
|
Packit Service |
a2489d |
#endif
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
switch((open_mode)mode)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
case CLOSED:
|
|
Packit Service |
a2489d |
case CONNECT_VERIFY:
|
|
Packit Service |
a2489d |
abort(); // cannot happen
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
case QUOTE_CMD:
|
|
Packit Service |
a2489d |
switch(special)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
case HTTP_POST:
|
|
Packit Service |
a2489d |
entity_size=special_data.length();
|
|
Packit Service |
a2489d |
goto send_post;
|
|
Packit Service |
a2489d |
case HTTP_MOVE:
|
|
Packit Service |
a2489d |
case HTTP_COPY:
|
|
Packit Service |
a2489d |
SendMethod(special==HTTP_MOVE?"MOVE":"COPY",efile);
|
|
Packit Service |
a2489d |
Send("Destination: %s\r\n",special_data.get());
|
|
Packit Service |
a2489d |
break;
|
|
Packit Service |
a2489d |
case HTTP_PROPFIND:
|
|
Packit Service |
a2489d |
SendMethod("PROPFIND",efile);
|
|
Packit Service |
a2489d |
Send("Depth: 1\r\n"); // directory listing required
|
|
Packit Service |
a2489d |
break;
|
|
Packit Service |
a2489d |
case HTTP_NONE:
|
|
Packit Service |
a2489d |
abort(); // cannot happen
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
break;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
case LIST:
|
|
Packit Service |
a2489d |
case CHANGE_MODE:
|
|
Packit Service |
a2489d |
case LINK:
|
|
Packit Service |
a2489d |
case SYMLINK:
|
|
Packit Service |
a2489d |
abort(); // unsupported
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
case RETRIEVE:
|
|
Packit Service |
a2489d |
retrieve:
|
|
Packit Service |
a2489d |
SendMethod("GET",efile);
|
|
Packit Service |
a2489d |
if(pos>0 && !no_ranges)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
if(limit==FILE_END)
|
|
Packit Service |
a2489d |
Send("Range: bytes=%lld-\r\n",(long long)pos);
|
|
Packit Service |
a2489d |
else
|
|
Packit Service |
a2489d |
Send("Range: bytes=%lld-%lld\r\n",(long long)pos,(long long)limit-1);
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
break;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
case STORE:
|
|
Packit Service |
a2489d |
if(sending_proppatch) {
|
|
Packit Service |
a2489d |
SendProppatch(efile);
|
|
Packit Service |
a2489d |
break;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
if(hftp || strcasecmp(Query("put-method",hostname),"POST"))
|
|
Packit Service |
a2489d |
SendMethod("PUT",efile);
|
|
Packit Service |
a2489d |
else
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
send_post:
|
|
Packit Service |
a2489d |
SendMethod("POST",efile);
|
|
Packit Service |
a2489d |
pos=0;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
if(entity_size>=0)
|
|
Packit Service |
a2489d |
Send("Content-length: %lld\r\n",(long long)(entity_size-pos));
|
|
Packit Service |
a2489d |
if(pos>0 && entity_size<0)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
request_pos=pos;
|
|
Packit Service |
a2489d |
if(limit==FILE_END)
|
|
Packit Service |
a2489d |
Send("Range: bytes=%lld-\r\n",(long long)pos);
|
|
Packit Service |
a2489d |
else
|
|
Packit Service |
a2489d |
Send("Range: bytes=%lld-%lld\r\n",(long long)pos,(long long)limit-1);
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
else if(pos>0)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
request_pos=pos;
|
|
Packit Service |
a2489d |
Send("Range: bytes=%lld-%lld/%lld\r\n",(long long)pos,
|
|
Packit Service |
a2489d |
(long long)((limit==FILE_END || limit>entity_size ? entity_size : limit)-1),
|
|
Packit Service |
a2489d |
(long long)entity_size);
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
if(entity_date!=NO_DATE)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
Send("Last-Modified: %s\r\n",FormatLastModified(entity_date).get());
|
|
Packit Service |
a2489d |
Send("X-OC-MTime: %ld\r\n",(long)entity_date); // for OwnCloud
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
break;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
case CHANGE_DIR:
|
|
Packit Service |
a2489d |
case LONG_LIST:
|
|
Packit Service |
a2489d |
case MP_LIST:
|
|
Packit Service |
a2489d |
case MAKE_DIR:
|
|
Packit Service |
a2489d |
if(last_char(efile)!='/' && add_slash)
|
|
Packit Service |
a2489d |
efile.append('/');
|
|
Packit Service |
a2489d |
if(mode==CHANGE_DIR)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
if(use_propfind_now)
|
|
Packit Service |
a2489d |
SendPropfind(efile,0);
|
|
Packit Service |
a2489d |
else
|
|
Packit Service |
a2489d |
SendMethod("HEAD",efile);
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
else if(mode==LONG_LIST)
|
|
Packit Service |
a2489d |
goto retrieve;
|
|
Packit Service |
a2489d |
else if(mode==MAKE_DIR)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
if(QueryBool("use-mkcol"))
|
|
Packit Service |
a2489d |
SendMethod("MKCOL",efile);
|
|
Packit Service |
a2489d |
else
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
SendMethod("PUT",efile);
|
|
Packit Service |
a2489d |
Send("Content-Length: 0\r\n");
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
pos=entity_size=0;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
else if(mode==MP_LIST)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
SendPropfind(efile,1);
|
|
Packit Service |
a2489d |
pos=0;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
break;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
case(REMOVE):
|
|
Packit Service |
a2489d |
SendMethod("DELETE",efile);
|
|
Packit Service |
a2489d |
Send("Depth: 0\r\n"); // deny directory removal
|
|
Packit Service |
a2489d |
break;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
case(REMOVE_DIR):
|
|
Packit Service |
a2489d |
if(efile.last_char()!='/')
|
|
Packit Service |
a2489d |
efile.append('/');
|
|
Packit Service |
a2489d |
SendMethod("DELETE",efile);
|
|
Packit Service |
a2489d |
break;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
case ARRAY_INFO:
|
|
Packit Service |
a2489d |
if(use_propfind_now)
|
|
Packit Service |
a2489d |
SendPropfind(efile,0);
|
|
Packit Service |
a2489d |
else
|
|
Packit Service |
a2489d |
SendMethod("HEAD",efile);
|
|
Packit Service |
a2489d |
break;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
case RENAME:
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
SendMethod("MOVE",efile);
|
|
Packit Service |
a2489d |
Send("Destination: %s\r\n",GetFileURL(file1).get());
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
if(proxy && !https)
|
|
Packit Service |
a2489d |
SendProxyAuth();
|
|
Packit Service |
a2489d |
SendAuth();
|
|
Packit Service |
a2489d |
if(no_cache || no_cache_this)
|
|
Packit Service |
a2489d |
Send("Pragma: no-cache\r\n"); // for HTTP/1.0 compatibility
|
|
Packit Service |
a2489d |
SendCacheControl();
|
|
Packit Service |
a2489d |
if(mode==ARRAY_INFO && !use_head)
|
|
Packit Service |
a2489d |
connection="close";
|
|
Packit Service |
a2489d |
else if(!ModeIs(STORE))
|
|
Packit Service |
a2489d |
connection="keep-alive";
|
|
Packit Service |
a2489d |
if(mode!=ARRAY_INFO || connection)
|
|
Packit Service |
a2489d |
Send("Connection: %s\r\n",connection?connection:"close");
|
|
Packit Service |
a2489d |
Send("\r\n");
|
|
Packit Service |
a2489d |
if(special==HTTP_POST)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
if(special_data)
|
|
Packit Service |
a2489d |
Send("%s",special_data.get());
|
|
Packit Service |
a2489d |
entity_size=NO_SIZE;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
else if(!xstrcmp(last_method,"PROPFIND"))
|
|
Packit Service |
a2489d |
SendPropfindBody();
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
keep_alive=false;
|
|
Packit Service |
a2489d |
chunked=false;
|
|
Packit Service |
a2489d |
chunked_trailer=false;
|
|
Packit Service |
a2489d |
chunk_size=CHUNK_SIZE_UNKNOWN;
|
|
Packit Service |
a2489d |
chunk_pos=0;
|
|
Packit Service |
a2489d |
request_pos=0;
|
|
Packit Service |
a2489d |
inflate=0;
|
|
Packit Service |
a2489d |
no_ranges=!QueryBool("use-range",hostname);
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
conn->send_buf->SetPos(0);
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
int Http::SendArrayInfoRequest()
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
// skip to next needed file
|
|
Packit Service |
a2489d |
for(FileInfo *fi=fileset_for_info->curr(); fi; fi=fileset_for_info->next())
|
|
Packit Service |
a2489d |
if(fi->need)
|
|
Packit Service |
a2489d |
break;
|
|
Packit Service |
a2489d |
if(array_send<fileset_for_info->curr_index())
|
|
Packit Service |
a2489d |
array_send=fileset_for_info->curr_index();
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
if(state!=CONNECTED)
|
|
Packit Service |
a2489d |
return 0;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
int m=1;
|
|
Packit Service |
a2489d |
if(keep_alive && use_head)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
m=keep_alive_max;
|
|
Packit Service |
a2489d |
if(m==-1)
|
|
Packit Service |
a2489d |
m=100;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
int req_count=0;
|
|
Packit Service |
a2489d |
while(array_send-fileset_for_info->curr_index()
|
|
Packit Service |
a2489d |
&& array_send<fileset_for_info->count())
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
FileInfo *fi=(*fileset_for_info)[array_send++];
|
|
Packit Service |
a2489d |
if(fi->need==0)
|
|
Packit Service |
a2489d |
continue;
|
|
Packit Service |
a2489d |
xstring *name=&fi->name;
|
|
Packit Service |
a2489d |
if(fi->filetype==fi->DIRECTORY && name->last_char()!='/') {
|
|
Packit Service |
a2489d |
name=&xstring::get_tmp(*name);
|
|
Packit Service |
a2489d |
name->append('/');
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
if(fi->uri)
|
|
Packit Service |
a2489d |
file_url.set(dir_file(GetConnectURL(),fi->uri));
|
|
Packit Service |
a2489d |
else
|
|
Packit Service |
a2489d |
file_url.unset();
|
|
Packit Service |
a2489d |
SendRequest(array_send==fileset_for_info->count()-1 ? 0 : "keep-alive", *name);
|
|
Packit Service |
a2489d |
req_count++;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
return req_count;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
void Http::ProceedArrayInfo()
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
for(;;)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
// skip to next needed file
|
|
Packit Service |
a2489d |
FileInfo *fi=fileset_for_info->next();
|
|
Packit Service |
a2489d |
if(!fi || fi->need)
|
|
Packit Service |
a2489d |
break;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
if(!fileset_for_info->curr())
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
LogNote(10,"that was the last file info");
|
|
Packit Service |
a2489d |
// received all requested info.
|
|
Packit Service |
a2489d |
state=DONE;
|
|
Packit Service |
a2489d |
return;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
// we can avoid reconnection if server supports it.
|
|
Packit Service |
a2489d |
if(keep_alive && (keep_alive_max>1 || keep_alive_max==-1)
|
|
Packit Service |
a2489d |
&& (use_head || use_propfind_now))
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
// we'll have to receive next header, unset the status
|
|
Packit Service |
a2489d |
status.set(0);
|
|
Packit Service |
a2489d |
status_code=0;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
state=CONNECTED;
|
|
Packit Service |
a2489d |
SendArrayInfoRequest();
|
|
Packit Service |
a2489d |
state=RECEIVING_HEADER;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
else
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
Disconnect();
|
|
Packit Service |
a2489d |
DontSleep();
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
void Http::NewAuth(const char *hdr,HttpAuth::target_t target,const char *user,const char *pass)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
if(!user || !pass)
|
|
Packit Service |
a2489d |
return;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
// FIXME: keep a request queue, get the URI from the queue.
|
|
Packit Service |
a2489d |
const char *uri=GetFileURL(file,NO_USER);
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
Ref<HttpAuth::Challenge> chal(new HttpAuth::Challenge(hdr));
|
|
Packit Service |
a2489d |
bool stale=chal->GetParam("stale").eq_nc("true");
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
if(auth_sent[target]>(stale?1:0))
|
|
Packit Service |
a2489d |
return;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
HttpAuth::scheme_t new_scheme=chal->GetSchemeCode();
|
|
Packit Service |
a2489d |
if(new_scheme<=auth_scheme[target])
|
|
Packit Service |
a2489d |
return;
|
|
Packit Service |
a2489d |
if(HttpAuth::New(target,uri,chal.borrow(),user,pass))
|
|
Packit Service |
a2489d |
auth_scheme[target]=new_scheme;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
void Http::HandleHeaderLine(const char *name,const char *value)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
// use a perfect hash
|
|
Packit Service |
a2489d |
#define hh(L,C) ((L)+(C)*3)
|
|
Packit Service |
a2489d |
#define hhc(S,C) hh(sizeof((S))-1,(C))
|
|
Packit Service |
a2489d |
#define case_hh(S,C) case hhc((S),(C)): if(strcasecmp(name,(S))) break;
|
|
Packit Service |
a2489d |
switch(hh(strlen(name),c_toupper(name[0]))) {
|
|
Packit Service |
a2489d |
case_hh("Content-Length",'C') {
|
|
Packit Service |
a2489d |
long long bs=0;
|
|
Packit Service |
a2489d |
if(1!=sscanf(value,"%lld",&bs))
|
|
Packit Service |
a2489d |
return;
|
|
Packit Service |
a2489d |
if(bs<0) // try to workaround broken servers
|
|
Packit Service |
a2489d |
bs+=0x100000000LL;
|
|
Packit Service |
a2489d |
body_size=bs;
|
|
Packit Service |
a2489d |
if(mode==ARRAY_INFO && H_2XX(status_code)
|
|
Packit Service |
a2489d |
&& xstrcmp(last_method,"PROPFIND"))
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
FileInfo *fi=fileset_for_info->curr();
|
|
Packit Service |
a2489d |
fi->SetSize(body_size);
|
|
Packit Service |
a2489d |
TrySuccess();
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
return;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
case_hh("Content-Range",'C') {
|
|
Packit Service |
a2489d |
long long first,last,fsize;
|
|
Packit Service |
a2489d |
if(H_REQUESTED_RANGE_NOT_SATISFIABLE(status_code))
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
if(sscanf(value,"%*[^/]/%lld",&fsize)!=1)
|
|
Packit Service |
a2489d |
return;
|
|
Packit Service |
a2489d |
if(opt_size)
|
|
Packit Service |
a2489d |
*opt_size=fsize;
|
|
Packit Service |
a2489d |
return;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
if(sscanf(value,"%*s %lld-%lld/%lld",&first,&last,&fsize)!=3)
|
|
Packit Service |
a2489d |
return;
|
|
Packit Service |
a2489d |
real_pos=first;
|
|
Packit Service |
a2489d |
if(last==-1)
|
|
Packit Service |
a2489d |
last=fsize-first-1;
|
|
Packit Service |
a2489d |
if(body_size<0)
|
|
Packit Service |
a2489d |
body_size=last-first+1;
|
|
Packit Service |
a2489d |
if(!ModeIs(STORE) && !ModeIs(MAKE_DIR))
|
|
Packit Service |
a2489d |
entity_size=fsize;
|
|
Packit Service |
a2489d |
if(opt_size && H_2XX(status_code))
|
|
Packit Service |
a2489d |
*opt_size=fsize;
|
|
Packit Service |
a2489d |
return;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
case_hh("Last-Modified",'L') {
|
|
Packit Service |
a2489d |
if(!H_2XX(status_code))
|
|
Packit Service |
a2489d |
return;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
time_t t=Http::atotm(value);
|
|
Packit Service |
a2489d |
if(t==ATOTM_ERROR)
|
|
Packit Service |
a2489d |
return;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
if(opt_date)
|
|
Packit Service |
a2489d |
*opt_date=t;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
if(mode==ARRAY_INFO && !propfind)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
FileInfo *fi=fileset_for_info->curr();
|
|
Packit Service |
a2489d |
fi->SetDate(t,0);
|
|
Packit Service |
a2489d |
TrySuccess();
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
return;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
case_hh("Location",'L')
|
|
Packit Service |
a2489d |
if(value[0]=='/' && value[1]=='/')
|
|
Packit Service |
a2489d |
location.vset(GetProto(),":",value,NULL);
|
|
Packit Service |
a2489d |
else if(value[0]=='/')
|
|
Packit Service |
a2489d |
location.vset(GetConnectURL().get(),value,NULL);
|
|
Packit Service |
a2489d |
else
|
|
Packit Service |
a2489d |
location.set(value);
|
|
Packit Service |
a2489d |
return;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
case_hh("Retry-After",'R')
|
|
Packit Service |
a2489d |
retry_after=0;
|
|
Packit Service |
a2489d |
sscanf(value,"%ld",&retry_after);
|
|
Packit Service |
a2489d |
return;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
case_hh("Keep-Alive",'K') {
|
|
Packit Service |
a2489d |
keep_alive=true;
|
|
Packit Service |
a2489d |
const char *m=strstr(value,"max=");
|
|
Packit Service |
a2489d |
if(m) {
|
|
Packit Service |
a2489d |
if(sscanf(m+4,"%d",&keep_alive_max)!=1)
|
|
Packit Service |
a2489d |
keep_alive=false;
|
|
Packit Service |
a2489d |
} else
|
|
Packit Service |
a2489d |
keep_alive_max=100;
|
|
Packit Service |
a2489d |
return;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
case_hh("Proxy-Connection",'P')
|
|
Packit Service |
a2489d |
goto case_Connection;
|
|
Packit Service |
a2489d |
case_hh("Connection",'C')
|
|
Packit Service |
a2489d |
case_Connection:
|
|
Packit Service |
a2489d |
if(!strcasecmp(value,"keep-alive"))
|
|
Packit Service |
a2489d |
keep_alive=true;
|
|
Packit Service |
a2489d |
else if(!strcasecmp(value,"close"))
|
|
Packit Service |
a2489d |
keep_alive=false;
|
|
Packit Service |
a2489d |
return;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
case_hh("Transfer-Encoding",'T')
|
|
Packit Service |
a2489d |
if(!strcasecmp(value,"identity"))
|
|
Packit Service |
a2489d |
return;
|
|
Packit Service |
a2489d |
if(!strcasecmp(value,"chunked"))
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
chunked=true;
|
|
Packit Service |
a2489d |
chunked_trailer=false;
|
|
Packit Service |
a2489d |
chunk_size=CHUNK_SIZE_UNKNOWN; // expecting first chunk
|
|
Packit Service |
a2489d |
chunk_pos=0;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
return;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
case_hh("Content-Encoding",'C')
|
|
Packit Service |
a2489d |
content_encoding.set(value);
|
|
Packit Service |
a2489d |
return;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
case_hh("Accept-Ranges",'A')
|
|
Packit Service |
a2489d |
if(!strcasecmp(value,"none"))
|
|
Packit Service |
a2489d |
no_ranges=true;
|
|
Packit Service |
a2489d |
if(strstr(value,"bytes"))
|
|
Packit Service |
a2489d |
seen_ranges_bytes=true;
|
|
Packit Service |
a2489d |
return;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
case_hh("Set-Cookie",'S')
|
|
Packit Service |
a2489d |
if(!hftp && QueryBool("set-cookies",hostname))
|
|
Packit Service |
a2489d |
SetCookie(value);
|
|
Packit Service |
a2489d |
return;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
case_hh("Content-Disposition",'C') {
|
|
Packit Service |
a2489d |
const char *filename=strstr(value,"filename=");
|
|
Packit Service |
a2489d |
if(!filename)
|
|
Packit Service |
a2489d |
return;
|
|
Packit Service |
a2489d |
filename=HttpHeader::extract_quoted_value(filename+9);
|
|
Packit Service |
a2489d |
SetSuggestedFileName(filename);
|
|
Packit Service |
a2489d |
return;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
case_hh("Content-Type",'C') {
|
|
Packit Service |
a2489d |
entity_content_type.set(value);
|
|
Packit Service |
a2489d |
const char *cs=strstr(value,"charset=");
|
|
Packit Service |
a2489d |
if(cs)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
cs=HttpHeader::extract_quoted_value(cs+8);
|
|
Packit Service |
a2489d |
entity_charset.set(cs);
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
return;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
case_hh("WWW-Authenticate",'W') {
|
|
Packit Service |
a2489d |
if(status_code!=H_Unauthorized)
|
|
Packit Service |
a2489d |
return;
|
|
Packit Service |
a2489d |
if(user && pass)
|
|
Packit Service |
a2489d |
NewAuth(value,HttpAuth::WWW,user,pass);
|
|
Packit Service |
a2489d |
else
|
|
Packit Service |
a2489d |
NewAuth(value,HttpAuth::WWW,auth_user,auth_pass);
|
|
Packit Service |
a2489d |
return;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
case_hh("Proxy-Authenticate",'P') {
|
|
Packit Service |
a2489d |
if(status_code!=H_Proxy_Authentication_Required)
|
|
Packit Service |
a2489d |
return;
|
|
Packit Service |
a2489d |
NewAuth(value,HttpAuth::PROXY,proxy_user,proxy_pass);
|
|
Packit Service |
a2489d |
return;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
case_hh("X-OC-MTime",'X') {
|
|
Packit Service |
a2489d |
if(!strcasecmp(value,"accepted"))
|
|
Packit Service |
a2489d |
entity_date_set=true;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
default:
|
|
Packit Service |
a2489d |
break;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
LogNote(10,"unhandled header line `%s'",name);
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
static
|
|
Packit Service |
a2489d |
const char *find_eol(const char *p,int len,int *eol_size)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
*eol_size=1;
|
|
Packit Service |
a2489d |
for(int i=0; i
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
if(p[0]=='\n')
|
|
Packit Service |
a2489d |
return p;
|
|
Packit Service |
a2489d |
if(i+1
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
*eol_size=2;
|
|
Packit Service |
a2489d |
return p;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
*eol_size=0;
|
|
Packit Service |
a2489d |
return 0;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
void Http::GetBetterConnection(int level)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
if(level==0)
|
|
Packit Service |
a2489d |
return;
|
|
Packit Service |
a2489d |
for(FA *fo=FirstSameSite(); fo!=0; fo=NextSameSite(fo))
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
Http *o=(Http*)fo; // we are sure it is Http.
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
if(!o->conn || o->state==CONNECTING)
|
|
Packit Service |
a2489d |
continue;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
if(o->tunnel_state==TUNNEL_WAITING)
|
|
Packit Service |
a2489d |
continue;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
if(o->state!=CONNECTED || o->mode!=CLOSED)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
if(level<2)
|
|
Packit Service |
a2489d |
continue;
|
|
Packit Service |
a2489d |
if(!connection_takeover || (o->priority>=priority && !o->IsSuspended()))
|
|
Packit Service |
a2489d |
continue;
|
|
Packit Service |
a2489d |
o->Disconnect();
|
|
Packit Service |
a2489d |
return;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
// so borrow the connection
|
|
Packit Service |
a2489d |
MoveConnectionHere(o);
|
|
Packit Service |
a2489d |
return;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
int Http::Do()
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
int m=STALL;
|
|
Packit Service |
a2489d |
int res;
|
|
Packit Service |
a2489d |
const char *error;
|
|
Packit Service |
a2489d |
const char *buf;
|
|
Packit Service |
a2489d |
int len;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
// check if idle time exceeded
|
|
Packit Service |
a2489d |
if(mode==CLOSED && conn && idle_timer.Stopped())
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
LogNote(1,_("Closing idle connection"));
|
|
Packit Service |
a2489d |
Disconnect();
|
|
Packit Service |
a2489d |
return m;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
if(home.path==0)
|
|
Packit Service |
a2489d |
set_home(default_cwd);
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
if(Error())
|
|
Packit Service |
a2489d |
return m;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
if(propfind)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
if(propfind->Error())
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
propfind=0;
|
|
Packit Service |
a2489d |
if(mode==CHANGE_DIR)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
SetError(NO_FILE,propfind->ErrorText());
|
|
Packit Service |
a2489d |
return MOVED;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
if(propfind->ErrorFatal())
|
|
Packit Service |
a2489d |
fileset_for_info->next();
|
|
Packit Service |
a2489d |
Disconnect();
|
|
Packit Service |
a2489d |
return MOVED;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
if(propfind->Eof())
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
LogNote(9,"got EOF on PROPFIND reply");
|
|
Packit Service |
a2489d |
const char *b;
|
|
Packit Service |
a2489d |
int len;
|
|
Packit Service |
a2489d |
propfind->Get(&b,&len;;
|
|
Packit Service |
a2489d |
Ref<FileSet> fs(HttpListInfo::ParseProps(b,len,GetCwd()));
|
|
Packit Service |
a2489d |
propfind=0;
|
|
Packit Service |
a2489d |
if(fs)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
if(mode==CHANGE_DIR)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
fs->rewind();
|
|
Packit Service |
a2489d |
FileInfo *fi=fs->curr();
|
|
Packit Service |
a2489d |
if(fi && fi->Has(fi->TYPE))
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
LogNote(9,"new-cwd: %s",fi->GetLongName());
|
|
Packit Service |
a2489d |
new_cwd->is_file=(fi->filetype!=fi->DIRECTORY);
|
|
Packit Service |
a2489d |
if(new_cwd->url.last_char()=='/' && new_cwd->is_file)
|
|
Packit Service |
a2489d |
new_cwd->url.rtrim('/');
|
|
Packit Service |
a2489d |
else if(new_cwd->url.last_char()!='/' && !new_cwd->is_file)
|
|
Packit Service |
a2489d |
new_cwd->url.append('/');
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
else if(mode==ARRAY_INFO)
|
|
Packit Service |
a2489d |
fileset_for_info->Merge(fs);
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
m=MOVED;
|
|
Packit Service |
a2489d |
state=DONE;
|
|
Packit Service |
a2489d |
if(mode==CHANGE_DIR)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
cwd.Set(new_cwd);
|
|
Packit Service |
a2489d |
cache->SetDirectory(this, "", !cwd.is_file);
|
|
Packit Service |
a2489d |
return m;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
else if(mode==ARRAY_INFO)
|
|
Packit Service |
a2489d |
ProceedArrayInfo();
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
switch(state)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
case DISCONNECTED:
|
|
Packit Service |
a2489d |
if(mode==CLOSED || !hostname)
|
|
Packit Service |
a2489d |
return m;
|
|
Packit Service |
a2489d |
if(ModeIs(STORE) && pos>0 && entity_size>=0 && pos>=entity_size)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
state=DONE;
|
|
Packit Service |
a2489d |
return MOVED;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
if(mode==ARRAY_INFO)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
// check if we have anything to request
|
|
Packit Service |
a2489d |
SendArrayInfoRequest();
|
|
Packit Service |
a2489d |
if(!fileset_for_info->curr())
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
state=DONE;
|
|
Packit Service |
a2489d |
return MOVED;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
if(!hftp && mode==QUOTE_CMD && !special)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
handle_quote_cmd:
|
|
Packit Service |
a2489d |
if(file && !strncasecmp(file,"Set-Cookie ",11))
|
|
Packit Service |
a2489d |
SetCookie(file+11);
|
|
Packit Service |
a2489d |
else if(file && !strncasecmp(file,"POST ",5))
|
|
Packit Service |
a2489d |
special=HTTP_POST;
|
|
Packit Service |
a2489d |
else if(file && !strncasecmp(file,"COPY ",5))
|
|
Packit Service |
a2489d |
special=HTTP_COPY;
|
|
Packit Service |
a2489d |
else if(file && !strncasecmp(file,"MOVE ",5))
|
|
Packit Service |
a2489d |
special=HTTP_MOVE;
|
|
Packit Service |
a2489d |
else if(file && !strncasecmp(file,"PROPFIND ",9))
|
|
Packit Service |
a2489d |
special=HTTP_PROPFIND;
|
|
Packit Service |
a2489d |
else
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
SetError(NOT_SUPP,0);
|
|
Packit Service |
a2489d |
return MOVED;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
if(special)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
// METHOD encoded_path data
|
|
Packit Service |
a2489d |
const char *scan=file;
|
|
Packit Service |
a2489d |
while(*scan && *scan!=' ')
|
|
Packit Service |
a2489d |
scan++;
|
|
Packit Service |
a2489d |
while(*scan==' ')
|
|
Packit Service |
a2489d |
scan++;
|
|
Packit Service |
a2489d |
file_url.set(https?"https://":"http://");
|
|
Packit Service |
a2489d |
AppendHostEncoded(file_url,hostname);
|
|
Packit Service |
a2489d |
if(portname)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
file_url.append(':');
|
|
Packit Service |
a2489d |
file_url.append_url_encoded(portname,URL_PORT_UNSAFE);
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
if(*scan!='/' && cwd)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
if(cwd[0]!='/')
|
|
Packit Service |
a2489d |
file_url.append('/');
|
|
Packit Service |
a2489d |
file_url.append_url_encoded(cwd,URL_PATH_UNSAFE);
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
if(*scan!='/' && file_url.last_char()!='/')
|
|
Packit Service |
a2489d |
file_url.append('/');
|
|
Packit Service |
a2489d |
file_url.append(scan);
|
|
Packit Service |
a2489d |
file_url.truncate_at(' ');
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
scan=strchr(scan,' ');
|
|
Packit Service |
a2489d |
while(scan && *scan==' ')
|
|
Packit Service |
a2489d |
scan++;
|
|
Packit Service |
a2489d |
special_data.set(scan);
|
|
Packit Service |
a2489d |
return MOVED;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
state=DONE;
|
|
Packit Service |
a2489d |
return MOVED;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
if(!special && !ModeSupported())
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
SetError(NOT_SUPP);
|
|
Packit Service |
a2489d |
return MOVED;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
if(hftp)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
if(!proxy)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
// problem here: hftp cannot work without proxy
|
|
Packit Service |
a2489d |
SetError(FATAL,_("ftp over http cannot work without proxy, set hftp:proxy."));
|
|
Packit Service |
a2489d |
return MOVED;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
// walk through Http classes and try to find identical idle session
|
|
Packit Service |
a2489d |
// first try "easy" cases of session take-over.
|
|
Packit Service |
a2489d |
for(int i=0; i<3; i++)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
if(i>=2 && (connection_limit==0 || connection_limit>CountConnections()))
|
|
Packit Service |
a2489d |
break;
|
|
Packit Service |
a2489d |
GetBetterConnection(i);
|
|
Packit Service |
a2489d |
if(state!=DISCONNECTED)
|
|
Packit Service |
a2489d |
return MOVED;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
if(!resolver && mode!=CONNECT_VERIFY && !ReconnectAllowed())
|
|
Packit Service |
a2489d |
return m;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
if(https)
|
|
Packit Service |
a2489d |
m|=Resolve(HTTPS_DEFAULT_PORT,"https","tcp");
|
|
Packit Service |
a2489d |
else
|
|
Packit Service |
a2489d |
m|=Resolve(HTTP_DEFAULT_PORT,"http","tcp");
|
|
Packit Service |
a2489d |
if(!peer)
|
|
Packit Service |
a2489d |
return m;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
if(mode==CONNECT_VERIFY)
|
|
Packit Service |
a2489d |
return m;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
if(!ReconnectAllowed())
|
|
Packit Service |
a2489d |
return m;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
if(!NextTry())
|
|
Packit Service |
a2489d |
return MOVED;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
retry_after=0;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
res=SocketCreateTCP(peer[peer_curr].sa.sa_family);
|
|
Packit Service |
a2489d |
if(res==-1)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
saved_errno=errno;
|
|
Packit Service |
a2489d |
if(peer_curr+1
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
peer_curr++;
|
|
Packit Service |
a2489d |
retries--;
|
|
Packit Service |
a2489d |
return MOVED;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
if(NonFatalError(saved_errno))
|
|
Packit Service |
a2489d |
return m;
|
|
Packit Service |
a2489d |
SetError(SEE_ERRNO,xstring::format(
|
|
Packit Service |
a2489d |
_("cannot create socket of address family %d"),
|
|
Packit Service |
a2489d |
peer[peer_curr].sa.sa_family));
|
|
Packit Service |
a2489d |
return MOVED;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
conn=new Connection(res,hostname);
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
SayConnectingTo();
|
|
Packit Service |
a2489d |
res=SocketConnect(conn->sock,&peer[peer_curr]);
|
|
Packit Service |
a2489d |
if(res==-1 && errno!=EINPROGRESS)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
saved_errno=errno;
|
|
Packit Service |
a2489d |
NextPeer();
|
|
Packit Service |
a2489d |
LogError(0,"connect: %s\n",strerror(saved_errno));
|
|
Packit Service |
a2489d |
Disconnect();
|
|
Packit Service |
a2489d |
if(NotSerious(saved_errno))
|
|
Packit Service |
a2489d |
return MOVED;
|
|
Packit Service |
a2489d |
goto system_error;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
state=CONNECTING;
|
|
Packit Service |
a2489d |
m=MOVED;
|
|
Packit Service |
a2489d |
timeout_timer.Reset();
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
case CONNECTING:
|
|
Packit Service |
a2489d |
res=Poll(conn->sock,POLLOUT,&error);
|
|
Packit Service |
a2489d |
if(res==-1)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
LogError(0,_("Socket error (%s) - reconnecting"),error);
|
|
Packit Service |
a2489d |
Disconnect(error);
|
|
Packit Service |
a2489d |
NextPeer();
|
|
Packit Service |
a2489d |
return MOVED;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
if(!(res&POLLOUT))
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
if(CheckTimeout())
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
NextPeer();
|
|
Packit Service |
a2489d |
return MOVED;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
Block(conn->sock,POLLOUT);
|
|
Packit Service |
a2489d |
return m;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
m=MOVED;
|
|
Packit Service |
a2489d |
state=CONNECTED;
|
|
Packit Service |
a2489d |
#if USE_SSL
|
|
Packit Service |
a2489d |
if(proxy?!strncmp(proxy,"https://",8):https)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
conn->MakeSSLBuffers();
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
else
|
|
Packit Service |
a2489d |
#endif
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
conn->MakeBuffers();
|
|
Packit Service |
a2489d |
#if USE_SSL
|
|
Packit Service |
a2489d |
if(proxy && https)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
// have to setup a tunnel.
|
|
Packit Service |
a2489d |
xstring ehost;
|
|
Packit Service |
a2489d |
AppendHostEncoded(ehost,hostname);
|
|
Packit Service |
a2489d |
const char *port_to_use=portname?portname.get():HTTPS_DEFAULT_PORT;
|
|
Packit Service |
a2489d |
const char *eport=url::encode(port_to_use,URL_PORT_UNSAFE);
|
|
Packit Service |
a2489d |
Send("CONNECT %s:%s HTTP/1.1\r\n",ehost.get(),eport);
|
|
Packit Service |
a2489d |
SendProxyAuth();
|
|
Packit Service |
a2489d |
Send("\r\n");
|
|
Packit Service |
a2489d |
tunnel_state=TUNNEL_WAITING;
|
|
Packit Service |
a2489d |
state=RECEIVING_HEADER;
|
|
Packit Service |
a2489d |
return MOVED;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
#endif // USE_SSL
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
/*fallthrough*/
|
|
Packit Service |
a2489d |
case CONNECTED:
|
|
Packit Service |
a2489d |
if(mode==CONNECT_VERIFY)
|
|
Packit Service |
a2489d |
return MOVED;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
if(mode==QUOTE_CMD && !special)
|
|
Packit Service |
a2489d |
goto handle_quote_cmd;
|
|
Packit Service |
a2489d |
if(conn->recv_buf->Eof())
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
LogError(0,_("Peer closed connection"));
|
|
Packit Service |
a2489d |
Disconnect();
|
|
Packit Service |
a2489d |
return MOVED;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
if(mode==CLOSED)
|
|
Packit Service |
a2489d |
return m;
|
|
Packit Service |
a2489d |
if(!special && !ModeSupported())
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
SetError(NOT_SUPP);
|
|
Packit Service |
a2489d |
return MOVED;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
ExpandTildeInCWD();
|
|
Packit Service |
a2489d |
if(ModeIs(STORE) && pos>0 && entity_size>=0 && pos>=entity_size)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
state=DONE;
|
|
Packit Service |
a2489d |
return MOVED;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
if(mode==ARRAY_INFO)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
if(SendArrayInfoRequest()==0) {
|
|
Packit Service |
a2489d |
// nothing to do
|
|
Packit Service |
a2489d |
state=DONE;
|
|
Packit Service |
a2489d |
return MOVED;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
else
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
LogNote(9,_("Sending request..."));
|
|
Packit Service |
a2489d |
SendRequest();
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
state=RECEIVING_HEADER;
|
|
Packit Service |
a2489d |
m=MOVED;
|
|
Packit Service |
a2489d |
if(ModeIs(STORE))
|
|
Packit Service |
a2489d |
rate_limit=new RateLimit(hostname);
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
case RECEIVING_HEADER:
|
|
Packit Service |
a2489d |
if(conn->send_buf->Error() || conn->recv_buf->Error())
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
if((ModeIs(STORE) || special) && status_code && !H_2XX(status_code))
|
|
Packit Service |
a2489d |
goto pre_RECEIVING_BODY; // assume error.
|
|
Packit Service |
a2489d |
handle_buf_error:
|
|
Packit Service |
a2489d |
if(conn->send_buf->Error())
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
LogError(0,"send: %s",conn->send_buf->ErrorText());
|
|
Packit Service |
a2489d |
if(conn->send_buf->ErrorFatal())
|
|
Packit Service |
a2489d |
SetError(FATAL,conn->send_buf->ErrorText());
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
if(conn->recv_buf->Error())
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
LogError(0,"recv: %s",conn->recv_buf->ErrorText());
|
|
Packit Service |
a2489d |
if(conn->recv_buf->ErrorFatal())
|
|
Packit Service |
a2489d |
SetError(FATAL,conn->recv_buf->ErrorText());
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
Disconnect();
|
|
Packit Service |
a2489d |
return MOVED;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
timeout_timer.Reset(conn->send_buf->EventTime());
|
|
Packit Service |
a2489d |
timeout_timer.Reset(conn->recv_buf->EventTime());
|
|
Packit Service |
a2489d |
if(CheckTimeout())
|
|
Packit Service |
a2489d |
return MOVED;
|
|
Packit Service |
a2489d |
conn->recv_buf->Get(&buf,&len;;
|
|
Packit Service |
a2489d |
if(!buf)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
// eof
|
|
Packit Service |
a2489d |
LogError(0,_("Hit EOF while fetching headers"));
|
|
Packit Service |
a2489d |
// workaround some broken servers
|
|
Packit Service |
a2489d |
if(H_REDIRECTED(status_code) && location)
|
|
Packit Service |
a2489d |
goto pre_RECEIVING_BODY;
|
|
Packit Service |
a2489d |
Disconnect();
|
|
Packit Service |
a2489d |
return MOVED;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
if(len>0)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
int eol_size;
|
|
Packit Service |
a2489d |
const char *eol=find_eol(buf,len,&eol_size);
|
|
Packit Service |
a2489d |
if(eol)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
// empty line indicates end of headers.
|
|
Packit Service |
a2489d |
if(eol==buf && status)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
LogRecv(4,"");
|
|
Packit Service |
a2489d |
conn->recv_buf->Skip(eol_size);
|
|
Packit Service |
a2489d |
if(tunnel_state==TUNNEL_WAITING)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
if(H_2XX(status_code))
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
#if USE_SSL
|
|
Packit Service |
a2489d |
if(https)
|
|
Packit Service |
a2489d |
conn->MakeSSLBuffers();
|
|
Packit Service |
a2489d |
#endif
|
|
Packit Service |
a2489d |
tunnel_state=TUNNEL_ESTABLISHED;
|
|
Packit Service |
a2489d |
ResetRequestData();
|
|
Packit Service |
a2489d |
state=CONNECTED;
|
|
Packit Service |
a2489d |
return MOVED;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
if(chunked_trailer)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
chunked_trailer=false;
|
|
Packit Service |
a2489d |
chunked=false;
|
|
Packit Service |
a2489d |
if(propfind) {
|
|
Packit Service |
a2489d |
// we avoid the DONE state since we have yet to handle propfind data
|
|
Packit Service |
a2489d |
propfind->PutEOF();
|
|
Packit Service |
a2489d |
state=CONNECTED;
|
|
Packit Service |
a2489d |
} else
|
|
Packit Service |
a2489d |
state=DONE;
|
|
Packit Service |
a2489d |
return MOVED;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
if(H_CONTINUE(status_code))
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
status.set(0);
|
|
Packit Service |
a2489d |
status_code=0;
|
|
Packit Service |
a2489d |
return MOVED;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
if(mode==ARRAY_INFO)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
if(!xstrcmp(last_method,"PROPFIND"))
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
if(H_UNSUPPORTED(status_code))
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
ResMgr::Set("http:use-propfind",hostname,"no");
|
|
Packit Service |
a2489d |
use_propfind_now=false;
|
|
Packit Service |
a2489d |
Disconnect();
|
|
Packit Service |
a2489d |
DontSleep();
|
|
Packit Service |
a2489d |
return MOVED;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
goto pre_RECEIVING_BODY;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
FileInfo *fi=fileset_for_info->curr();
|
|
Packit Service |
a2489d |
if(H_REDIRECTED(status_code)) {
|
|
Packit Service |
a2489d |
HandleRedirection();
|
|
Packit Service |
a2489d |
if(location)
|
|
Packit Service |
a2489d |
fi->SetRedirect(location);
|
|
Packit Service |
a2489d |
} else if(H_2XX(status_code) && !fi->Has(fi->TYPE)) {
|
|
Packit Service |
a2489d |
fi->SetType(last_uri.last_char()=='/'?fi->DIRECTORY:fi->NORMAL);
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
ProceedArrayInfo();
|
|
Packit Service |
a2489d |
return MOVED;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
else if(ModeIs(STORE) || ModeIs(MAKE_DIR) || sending_proppatch)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
if((sent_eot || pos==entity_size || sending_proppatch) && H_2XX(status_code))
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
state=DONE;
|
|
Packit Service |
a2489d |
Disconnect();
|
|
Packit Service |
a2489d |
state=DONE;
|
|
Packit Service |
a2489d |
if(ModeIs(STORE) && entity_date!=NO_DATE && !entity_date_set
|
|
Packit Service |
a2489d |
&& use_propfind_now) {
|
|
Packit Service |
a2489d |
// send PROPPATCH in a separate request.
|
|
Packit Service |
a2489d |
sending_proppatch=true;
|
|
Packit Service |
a2489d |
state=DISCONNECTED;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
return MOVED;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
if(H_2XX(status_code))
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
// should never happen
|
|
Packit Service |
a2489d |
LogError(0,"Unexpected success, the server did not accept full request body");
|
|
Packit Service |
a2489d |
Disconnect();
|
|
Packit Service |
a2489d |
return MOVED;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
// going to pre_RECEIVING_BODY to catch error
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
goto pre_RECEIVING_BODY;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
len=eol-buf;
|
|
Packit Service |
a2489d |
line.nset(buf,len);
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
conn->recv_buf->Skip(len+eol_size);
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
LogRecv(4,line);
|
|
Packit Service |
a2489d |
m=MOVED;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
if(status==0)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
// it's status line
|
|
Packit Service |
a2489d |
status.set(line);
|
|
Packit Service |
a2489d |
int ver_major,ver_minor;
|
|
Packit Service |
a2489d |
if(3!=sscanf(status,"HTTP/%d.%d %n%d",&ver_major,&ver_minor,
|
|
Packit Service |
a2489d |
&status_consumed,&status_code))
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
// simple 0.9 ?
|
|
Packit Service |
a2489d |
proto_version=0x09;
|
|
Packit Service |
a2489d |
status_code=H_Ok;
|
|
Packit Service |
a2489d |
LogError(0,_("Could not parse HTTP status line"));
|
|
Packit Service |
a2489d |
if(ModeIs(STORE))
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
state=DONE;
|
|
Packit Service |
a2489d |
Disconnect();
|
|
Packit Service |
a2489d |
state=DONE;
|
|
Packit Service |
a2489d |
return MOVED;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
conn->recv_buf->UnSkip(len+eol_size);
|
|
Packit Service |
a2489d |
goto pre_RECEIVING_BODY;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
proto_version=(ver_major<<4)+ver_minor;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
// HTTP/1.1 does keep-alive by default
|
|
Packit Service |
a2489d |
if(proto_version>=0x11)
|
|
Packit Service |
a2489d |
keep_alive=true;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
if(!H_2XX(status_code))
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
if(H_CONTINUE(status_code))
|
|
Packit Service |
a2489d |
return MOVED;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
if(H_5XX(status_code)) // server failed, try another
|
|
Packit Service |
a2489d |
NextPeer();
|
|
Packit Service |
a2489d |
if(status_code==H_Gateway_Timeout)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
const char *cc=Query("cache-control");
|
|
Packit Service |
a2489d |
if(cc && strstr(cc,"only-if-cached"))
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
if(mode!=ARRAY_INFO)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
SetError(NO_FILE,_("Object is not cached and http:cache-control has only-if-cached"));
|
|
Packit Service |
a2489d |
return MOVED;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
status_code=H_Not_Acceptable; // so that no retry will be attempted
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
// check for retriable codes
|
|
Packit Service |
a2489d |
if(H_TRANSIENT(status_code))
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
Disconnect();
|
|
Packit Service |
a2489d |
return MOVED;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
if(status_code==H_Too_Many_Requests)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
Disconnect();
|
|
Packit Service |
a2489d |
if(retry_after)
|
|
Packit Service |
a2489d |
reconnect_timer.StopDelayed(retry_after);
|
|
Packit Service |
a2489d |
return MOVED;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
if(mode==ARRAY_INFO)
|
|
Packit Service |
a2489d |
TrySuccess();
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
return MOVED;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
else
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
// header line.
|
|
Packit Service |
a2489d |
char *colon=strchr(line.get_non_const(),':');
|
|
Packit Service |
a2489d |
if(colon)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
*colon=0; // terminate the header tag
|
|
Packit Service |
a2489d |
const char *value=colon+1;
|
|
Packit Service |
a2489d |
while(*value==' ')
|
|
Packit Service |
a2489d |
value++;
|
|
Packit Service |
a2489d |
HandleHeaderLine(line,value);
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
if(ModeIs(STORE) && (!status || H_CONTINUE(status_code)) && !sent_eot)
|
|
Packit Service |
a2489d |
Block(conn->sock,POLLOUT);
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
return m;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
pre_RECEIVING_BODY:
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
// 204 No Content
|
|
Packit Service |
a2489d |
if(H_EMPTY(status_code) && body_size<0)
|
|
Packit Service |
a2489d |
body_size=0;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
if(H_REDIRECTED(status_code))
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
// check if it is redirection to the same server
|
|
Packit Service |
a2489d |
// or to directory instead of file.
|
|
Packit Service |
a2489d |
// FIXME.
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
if(H_REQUESTED_RANGE_NOT_SATISFIABLE(status_code))
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
// file is smaller than requested
|
|
Packit Service |
a2489d |
state=DONE;
|
|
Packit Service |
a2489d |
return MOVED;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
if((status_code==H_Unauthorized && auth_scheme[HttpAuth::WWW])
|
|
Packit Service |
a2489d |
|| (status_code==H_Proxy_Authentication_Required && auth_scheme[HttpAuth::PROXY])) {
|
|
Packit Service |
a2489d |
// retry with authentication
|
|
Packit Service |
a2489d |
retries--;
|
|
Packit Service |
a2489d |
state=RECEIVING_BODY;
|
|
Packit Service |
a2489d |
LogErrorText();
|
|
Packit Service |
a2489d |
Disconnect();
|
|
Packit Service |
a2489d |
DontSleep();
|
|
Packit Service |
a2489d |
return MOVED;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
if(!H_2XX(status_code))
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
xstring err;
|
|
Packit Service |
a2489d |
int code=NO_FILE;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
if(H_REDIRECTED(status_code))
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
HandleRedirection();
|
|
Packit Service |
a2489d |
err.setf("%s (%s -> %s)",status+status_consumed,file.get(),
|
|
Packit Service |
a2489d |
location?location.get():"nowhere");
|
|
Packit Service |
a2489d |
code=FILE_MOVED;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
else
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
const char *closure=file;
|
|
Packit Service |
a2489d |
if(H_UNSUPPORTED(status_code) || status_code==H_Method_Not_Allowed)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
if(H_UNSUPPORTED(status_code))
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
if(!xstrcmp(last_method,"PROPFIND"))
|
|
Packit Service |
a2489d |
ResMgr::Set("http:use-propfind",hostname,"no");
|
|
Packit Service |
a2489d |
if(!xstrcmp(last_method,"MKCOL"))
|
|
Packit Service |
a2489d |
ResMgr::Set("http:use-mkcol",hostname,"no");
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
if(mode==CHANGE_DIR && !xstrcmp(last_method,"PROPFIND"))
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
use_propfind_now=false;
|
|
Packit Service |
a2489d |
Disconnect();
|
|
Packit Service |
a2489d |
DontSleep();
|
|
Packit Service |
a2489d |
return MOVED;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
code=NOT_SUPP;
|
|
Packit Service |
a2489d |
closure=last_method;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
if(closure && closure[0])
|
|
Packit Service |
a2489d |
err.setf("%s (%s)",status+status_consumed,closure);
|
|
Packit Service |
a2489d |
else
|
|
Packit Service |
a2489d |
err.setf("%s (%s%s)",status+status_consumed,cwd.path.get(),
|
|
Packit Service |
a2489d |
(last_char(cwd)=='/')?"":"/");
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
state=RECEIVING_BODY;
|
|
Packit Service |
a2489d |
LogErrorText();
|
|
Packit Service |
a2489d |
if(mode==ARRAY_INFO)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
if(!H_TRANSIENT(status_code))
|
|
Packit Service |
a2489d |
fileset_for_info->next();
|
|
Packit Service |
a2489d |
Disconnect();
|
|
Packit Service |
a2489d |
DontSleep();
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
else
|
|
Packit Service |
a2489d |
SetError(code,err);
|
|
Packit Service |
a2489d |
return MOVED;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
if(!xstrcmp(last_method,"PROPFIND")
|
|
Packit Service |
a2489d |
&& (mode==ARRAY_INFO || mode==CHANGE_DIR)) {
|
|
Packit Service |
a2489d |
LogNote(9,"accepting XML for PROPFIND...");
|
|
Packit Service |
a2489d |
propfind=new IOBufferFileAccess(this);
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
if(mode==CHANGE_DIR && !propfind)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
cwd.Set(new_cwd);
|
|
Packit Service |
a2489d |
cache->SetDirectory(this, "", !cwd.is_file);
|
|
Packit Service |
a2489d |
state=DONE;
|
|
Packit Service |
a2489d |
return MOVED;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
// Many servers send application/x-gzip with x-gzip encoding,
|
|
Packit Service |
a2489d |
// don't decode in such a case.
|
|
Packit Service |
a2489d |
if(CompressedContentEncoding() && !CompressedContentType()
|
|
Packit Service |
a2489d |
&& QueryBool("decode",hostname)) {
|
|
Packit Service |
a2489d |
// inflated size is unknown beforehand
|
|
Packit Service |
a2489d |
entity_size=NO_SIZE;
|
|
Packit Service |
a2489d |
if(opt_size)
|
|
Packit Service |
a2489d |
*opt_size=NO_SIZE;
|
|
Packit Service |
a2489d |
// start the inflation
|
|
Packit Service |
a2489d |
inflate=new DirectedBuffer(DirectedBuffer::GET);
|
|
Packit Service |
a2489d |
inflate->SetTranslator(new DataInflator());
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
// sometimes it's possible to derive entity size from body size.
|
|
Packit Service |
a2489d |
if(entity_size==NO_SIZE && body_size!=NO_SIZE
|
|
Packit Service |
a2489d |
&& pos==0 && !ModeIs(STORE) && !ModeIs(MAKE_DIR) && !inflate) {
|
|
Packit Service |
a2489d |
entity_size=body_size;
|
|
Packit Service |
a2489d |
if(opt_size && H_2XX(status_code))
|
|
Packit Service |
a2489d |
*opt_size=body_size;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
LogNote(9,_("Receiving body..."));
|
|
Packit Service |
a2489d |
rate_limit=new RateLimit(hostname);
|
|
Packit Service |
a2489d |
if(real_pos<0) // assume Range: did not work
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
if(!ModeIs(STORE) && !ModeIs(MAKE_DIR) && body_size>=0)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
entity_size=body_size;
|
|
Packit Service |
a2489d |
if(opt_size && H_2XX(status_code))
|
|
Packit Service |
a2489d |
*opt_size=entity_size;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
real_pos=0;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
state=RECEIVING_BODY;
|
|
Packit Service |
a2489d |
m=MOVED;
|
|
Packit Service |
a2489d |
/*passthrough*/
|
|
Packit Service |
a2489d |
case RECEIVING_BODY:
|
|
Packit Service |
a2489d |
if(conn->recv_buf->Error() || conn->send_buf->Error())
|
|
Packit Service |
a2489d |
goto handle_buf_error;
|
|
Packit Service |
a2489d |
if(conn->recv_buf->Size()>=rate_limit->BytesAllowedToGet())
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
conn->recv_buf->Suspend();
|
|
Packit Service |
a2489d |
TimeoutS(1);
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
else if(conn->recv_buf->Size()>=max_buf)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
conn->recv_buf->Suspend();
|
|
Packit Service |
a2489d |
m=MOVED;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
else
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
if(conn->recv_buf->IsSuspended())
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
conn->recv_buf->Resume();
|
|
Packit Service |
a2489d |
if(conn->recv_buf->Size()>0 || (conn->recv_buf->Size()==0 && conn->recv_buf->Eof()))
|
|
Packit Service |
a2489d |
m=MOVED;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
timeout_timer.Reset(conn->send_buf->EventTime());
|
|
Packit Service |
a2489d |
timeout_timer.Reset(conn->recv_buf->EventTime());
|
|
Packit Service |
a2489d |
if(conn->recv_buf->Size()==0)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
// check if ranges were emulated by squid
|
|
Packit Service |
a2489d |
bool no_ranges_if_timeout=(bytes_received==0 && !seen_ranges_bytes);
|
|
Packit Service |
a2489d |
if(CheckTimeout())
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
if(no_ranges_if_timeout)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
no_ranges=true;
|
|
Packit Service |
a2489d |
real_pos=0; // so that pget would know immediately.
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
return MOVED;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
return m;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
case DONE:
|
|
Packit Service |
a2489d |
return m;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
return m;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
system_error:
|
|
Packit Service |
a2489d |
assert(saved_errno!=0);
|
|
Packit Service |
a2489d |
if(NonFatalError(saved_errno))
|
|
Packit Service |
a2489d |
return m;
|
|
Packit Service |
a2489d |
SetError(SEE_ERRNO,0);
|
|
Packit Service |
a2489d |
Disconnect();
|
|
Packit Service |
a2489d |
return MOVED;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
void Http::HandleRedirection()
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
bool is_url=(location && url::is_url(location));
|
|
Packit Service |
a2489d |
if(location && !is_url
|
|
Packit Service |
a2489d |
&& mode==QUOTE_CMD && !strncasecmp(file,"POST ",5)
|
|
Packit Service |
a2489d |
&& tunnel_state!=TUNNEL_WAITING)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
const char *the_file=file;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
const char *scan=file+5;
|
|
Packit Service |
a2489d |
while(*scan==' ')
|
|
Packit Service |
a2489d |
scan++;
|
|
Packit Service |
a2489d |
char *the_post_file=alloca_strdup(scan);
|
|
Packit Service |
a2489d |
char *space=strchr(the_post_file,' ');
|
|
Packit Service |
a2489d |
if(space)
|
|
Packit Service |
a2489d |
*space=0;
|
|
Packit Service |
a2489d |
the_file=the_post_file;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
char *new_location=alloca_strdup2(GetConnectURL(),
|
|
Packit Service |
a2489d |
strlen(the_file)+strlen(location));
|
|
Packit Service |
a2489d |
int p_ind=url::path_index(new_location);
|
|
Packit Service |
a2489d |
if(location[0]=='/')
|
|
Packit Service |
a2489d |
strcpy(new_location+p_ind,location);
|
|
Packit Service |
a2489d |
else
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
if(the_file[0]=='/')
|
|
Packit Service |
a2489d |
strcpy(new_location+p_ind,the_file);
|
|
Packit Service |
a2489d |
else
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
char *slash=strrchr(new_location,'/');
|
|
Packit Service |
a2489d |
strcpy(slash+1,the_file);
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
char *slash=strrchr(new_location,'/');
|
|
Packit Service |
a2489d |
strcpy(slash+1,location);
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
location.set(new_location);
|
|
Packit Service |
a2489d |
} else if(is_url && !hftp) {
|
|
Packit Service |
a2489d |
ParsedURL url(location);
|
|
Packit Service |
a2489d |
if(url.proto.eq(GetProto()) && !xstrcasecmp(url.host,hostname)
|
|
Packit Service |
a2489d |
&& user && !url.user) {
|
|
Packit Service |
a2489d |
// use the same user name after redirect to the same site.
|
|
Packit Service |
a2489d |
url.user.set(user);
|
|
Packit Service |
a2489d |
location.truncate();
|
|
Packit Service |
a2489d |
url.CombineTo(location);
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
FileAccess *Http::New() { return new Http(); }
|
|
Packit Service |
a2489d |
FileAccess *HFtp::New() { return new HFtp(); }
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
void Http::ClassInit()
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
// register the class
|
|
Packit Service |
a2489d |
Register("http",Http::New);
|
|
Packit Service |
a2489d |
Register("hftp",HFtp::New);
|
|
Packit Service |
a2489d |
#if USE_SSL
|
|
Packit Service |
a2489d |
Register("https",Https::New);
|
|
Packit Service |
a2489d |
#endif
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
void Http::SuspendInternal()
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
super::SuspendInternal();
|
|
Packit Service |
a2489d |
if(conn)
|
|
Packit Service |
a2489d |
conn->SuspendInternal();
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
void Http::ResumeInternal()
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
if(conn)
|
|
Packit Service |
a2489d |
conn->ResumeInternal();
|
|
Packit Service |
a2489d |
super::ResumeInternal();
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
int Http::Read(Buffer *buf,int size)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
if(Error())
|
|
Packit Service |
a2489d |
return error_code;
|
|
Packit Service |
a2489d |
if(mode==CLOSED)
|
|
Packit Service |
a2489d |
return 0;
|
|
Packit Service |
a2489d |
if(state==DONE)
|
|
Packit Service |
a2489d |
return 0; // eof
|
|
Packit Service |
a2489d |
int res=DO_AGAIN;
|
|
Packit Service |
a2489d |
if(state==RECEIVING_BODY && real_pos>=0)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
Enter(this);
|
|
Packit Service |
a2489d |
res=_Read(buf,size);
|
|
Packit Service |
a2489d |
if(res>0)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
pos+=res;
|
|
Packit Service |
a2489d |
if(rate_limit)
|
|
Packit Service |
a2489d |
rate_limit->BytesGot(res);
|
|
Packit Service |
a2489d |
TrySuccess();
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
Leave(this);
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
return res;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
void Http::_Skip(int to_skip)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
if(inflate)
|
|
Packit Service |
a2489d |
inflate->Skip(to_skip);
|
|
Packit Service |
a2489d |
else
|
|
Packit Service |
a2489d |
conn->recv_buf->Skip(to_skip);
|
|
Packit Service |
a2489d |
_UpdatePos(to_skip);
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
void Http::_UpdatePos(int to_skip)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
if(!inflate) {
|
|
Packit Service |
a2489d |
if(chunked)
|
|
Packit Service |
a2489d |
chunk_pos+=to_skip;
|
|
Packit Service |
a2489d |
bytes_received+=to_skip;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
real_pos+=to_skip;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
int Http::_Read(Buffer *buf,int size)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
const char *buf1;
|
|
Packit Service |
a2489d |
int size1;
|
|
Packit Service |
a2489d |
Buffer *src_buf=conn->recv_buf.get_non_const();
|
|
Packit Service |
a2489d |
get_again:
|
|
Packit Service |
a2489d |
if(conn->recv_buf->Size()==0 && conn->recv_buf->Error())
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
LogError(0,"recv: %s",conn->recv_buf->ErrorText());
|
|
Packit Service |
a2489d |
if(conn->recv_buf->ErrorFatal())
|
|
Packit Service |
a2489d |
SetError(FATAL,conn->recv_buf->ErrorText());
|
|
Packit Service |
a2489d |
Disconnect();
|
|
Packit Service |
a2489d |
return DO_AGAIN;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
conn->recv_buf->Get(&buf1,&size1);
|
|
Packit Service |
a2489d |
if(buf1==0) // eof
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
LogNote(9,_("Hit EOF"));
|
|
Packit Service |
a2489d |
if(bytes_received
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
LogError(0,_("Received not enough data, retrying"));
|
|
Packit Service |
a2489d |
Disconnect();
|
|
Packit Service |
a2489d |
return DO_AGAIN;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
return 0;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
if(!chunked)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
if(body_size>=0 && bytes_received>=body_size
|
|
Packit Service |
a2489d |
&& (!inflate || inflate->Size()==0))
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
LogNote(9,_("Received all"));
|
|
Packit Service |
a2489d |
return 0; // all received
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
if(entity_size>=0 && pos>=entity_size)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
LogNote(9,_("Received all (total)"));
|
|
Packit Service |
a2489d |
return 0;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
if(size1==0 && (!inflate || inflate->Size()==0))
|
|
Packit Service |
a2489d |
return DO_AGAIN;
|
|
Packit Service |
a2489d |
if(chunked && size1>0)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
if(chunked_trailer && state==RECEIVING_HEADER)
|
|
Packit Service |
a2489d |
return DO_AGAIN;
|
|
Packit Service |
a2489d |
const char *nl;
|
|
Packit Service |
a2489d |
if(chunk_size==CHUNK_SIZE_UNKNOWN) // expecting first/next chunk
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
nl=(const char*)memchr(buf1,'\n',size1);
|
|
Packit Service |
a2489d |
if(nl==0) // not yet
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
not_yet:
|
|
Packit Service |
a2489d |
if(conn->recv_buf->Eof())
|
|
Packit Service |
a2489d |
Disconnect(); // connection closed too early
|
|
Packit Service |
a2489d |
return DO_AGAIN;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
if(!is_ascii_xdigit(*buf1)
|
|
Packit Service |
a2489d |
|| sscanf(buf1,"%lx",&chunk_size)!=1)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
Fatal(_("chunked format violated"));
|
|
Packit Service |
a2489d |
return FATAL;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
conn->recv_buf->Skip(nl-buf1+1);
|
|
Packit Service |
a2489d |
chunk_pos=0;
|
|
Packit Service |
a2489d |
LogNote(9,"next chunk size: %ld",chunk_size);
|
|
Packit Service |
a2489d |
goto get_again;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
if(chunk_size==0) // eof
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
LogNote(9,_("Received last chunk"));
|
|
Packit Service |
a2489d |
// headers may follow
|
|
Packit Service |
a2489d |
chunked_trailer=true;
|
|
Packit Service |
a2489d |
state=RECEIVING_HEADER;
|
|
Packit Service |
a2489d |
body_size=bytes_received;
|
|
Packit Service |
a2489d |
Timeout(0);
|
|
Packit Service |
a2489d |
return DO_AGAIN;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
if(chunk_pos==chunk_size)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
if(size1<2)
|
|
Packit Service |
a2489d |
goto not_yet;
|
|
Packit Service |
a2489d |
if(buf1[0]!='\r' || buf1[1]!='\n')
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
Fatal(_("chunked format violated"));
|
|
Packit Service |
a2489d |
return FATAL;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
conn->recv_buf->Skip(2);
|
|
Packit Service |
a2489d |
chunk_size=CHUNK_SIZE_UNKNOWN;
|
|
Packit Service |
a2489d |
goto get_again;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
// ok, now we may get portion of data
|
|
Packit Service |
a2489d |
if(size1>chunk_size-chunk_pos)
|
|
Packit Service |
a2489d |
size1=chunk_size-chunk_pos;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
if(!chunked)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
// limit by body_size.
|
|
Packit Service |
a2489d |
if(body_size>=0 && size1+bytes_received>=body_size)
|
|
Packit Service |
a2489d |
size1=body_size-bytes_received;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
int bytes_allowed=0x10000000;
|
|
Packit Service |
a2489d |
if(rate_limit)
|
|
Packit Service |
a2489d |
bytes_allowed=rate_limit->BytesAllowedToGet();
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
if(inflate) {
|
|
Packit Service |
a2489d |
// do the inflation, if there are not enough inflated data
|
|
Packit Service |
a2489d |
if(size1>bytes_allowed)
|
|
Packit Service |
a2489d |
size1=bytes_allowed;
|
|
Packit Service |
a2489d |
if(inflate->Size()<size && size1>0) {
|
|
Packit Service |
a2489d |
inflate->PutTranslated(buf1,size1);
|
|
Packit Service |
a2489d |
conn->recv_buf->Skip(size1);
|
|
Packit Service |
a2489d |
if(chunked)
|
|
Packit Service |
a2489d |
chunk_pos+=size1;
|
|
Packit Service |
a2489d |
bytes_received+=size1;
|
|
Packit Service |
a2489d |
if(inflate->Error())
|
|
Packit Service |
a2489d |
SetError(FATAL,inflate->ErrorText());
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
inflate->Get(&buf1,&size1);
|
|
Packit Service |
a2489d |
src_buf=inflate.get_non_const();
|
|
Packit Service |
a2489d |
} else {
|
|
Packit Service |
a2489d |
if(size1>bytes_allowed)
|
|
Packit Service |
a2489d |
size1=bytes_allowed;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
if(size1==0)
|
|
Packit Service |
a2489d |
return DO_AGAIN;
|
|
Packit Service |
a2489d |
if(norest_manual && real_pos==0 && pos>0)
|
|
Packit Service |
a2489d |
return DO_AGAIN;
|
|
Packit Service |
a2489d |
if(real_pos
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
off_t to_skip=pos-real_pos;
|
|
Packit Service |
a2489d |
if(to_skip>size1)
|
|
Packit Service |
a2489d |
to_skip=size1;
|
|
Packit Service |
a2489d |
_Skip(to_skip);
|
|
Packit Service |
a2489d |
goto get_again;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
if(size>size1)
|
|
Packit Service |
a2489d |
size=size1;
|
|
Packit Service |
a2489d |
size=buf->MoveDataHere(src_buf,size);
|
|
Packit Service |
a2489d |
_UpdatePos(size);
|
|
Packit Service |
a2489d |
return size;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
int Http::Done()
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
if(mode==CLOSED)
|
|
Packit Service |
a2489d |
return OK;
|
|
Packit Service |
a2489d |
if(Error())
|
|
Packit Service |
a2489d |
return error_code;
|
|
Packit Service |
a2489d |
if(state==DONE)
|
|
Packit Service |
a2489d |
return OK;
|
|
Packit Service |
a2489d |
if(mode==CONNECT_VERIFY && (peer || conn))
|
|
Packit Service |
a2489d |
return OK;
|
|
Packit Service |
a2489d |
if((mode==REMOVE || mode==REMOVE_DIR || mode==RENAME)
|
|
Packit Service |
a2489d |
&& state==RECEIVING_BODY)
|
|
Packit Service |
a2489d |
return OK;
|
|
Packit Service |
a2489d |
return IN_PROGRESS;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
int Http::Buffered()
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
if(!ModeIs(STORE) || !conn || !conn->send_buf)
|
|
Packit Service |
a2489d |
return 0;
|
|
Packit Service |
a2489d |
return conn->send_buf->Size()+SocketBuffered(conn->sock);
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
int Http::Write(const void *buf,int size)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
if(!ModeIs(STORE))
|
|
Packit Service |
a2489d |
return(0);
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
Resume();
|
|
Packit Service |
a2489d |
Do();
|
|
Packit Service |
a2489d |
if(Error())
|
|
Packit Service |
a2489d |
return(error_code);
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
if(state!=RECEIVING_HEADER || status!=0 || conn->send_buf->Size()!=0)
|
|
Packit Service |
a2489d |
return DO_AGAIN;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
int allowed=rate_limit->BytesAllowedToPut();
|
|
Packit Service |
a2489d |
if(allowed==0)
|
|
Packit Service |
a2489d |
return DO_AGAIN;
|
|
Packit Service |
a2489d |
if(size>allowed)
|
|
Packit Service |
a2489d |
size=allowed;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
if(size+conn->send_buf->Size()>=max_buf)
|
|
Packit Service |
a2489d |
size=max_buf-conn->send_buf->Size();
|
|
Packit Service |
a2489d |
if(entity_size!=NO_SIZE && pos+size>entity_size)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
size=entity_size-pos;
|
|
Packit Service |
a2489d |
// tried to write more than originally requested. Make it retry with Open:
|
|
Packit Service |
a2489d |
if(size==0)
|
|
Packit Service |
a2489d |
return STORE_FAILED;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
if(size<=0)
|
|
Packit Service |
a2489d |
return 0;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
conn->send_buf->Put((const char*)buf,size);
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
if(retries>0 && conn->send_buf->GetPos()-conn->send_buf->Size()>Buffered()+0x1000)
|
|
Packit Service |
a2489d |
TrySuccess();
|
|
Packit Service |
a2489d |
rate_limit->BytesPut(size);
|
|
Packit Service |
a2489d |
pos+=size;
|
|
Packit Service |
a2489d |
real_pos+=size;
|
|
Packit Service |
a2489d |
return(size);
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
int Http::SendEOT()
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
if(sent_eot)
|
|
Packit Service |
a2489d |
return OK;
|
|
Packit Service |
a2489d |
if(Error())
|
|
Packit Service |
a2489d |
return(error_code);
|
|
Packit Service |
a2489d |
if(ModeIs(STORE))
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
if(state==RECEIVING_HEADER && conn->send_buf->Size()==0)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
if(entity_size==NO_SIZE || pos
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
shutdown(conn->sock,1);
|
|
Packit Service |
a2489d |
keep_alive=false;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
sent_eot=true;
|
|
Packit Service |
a2489d |
return(OK);
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
return(DO_AGAIN);
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
return(OK);
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
int Http::StoreStatus()
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
if(!sent_eot && state==RECEIVING_HEADER)
|
|
Packit Service |
a2489d |
SendEOT();
|
|
Packit Service |
a2489d |
return Done();
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
const char *Http::CurrentStatus()
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
switch(state)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
case DISCONNECTED:
|
|
Packit Service |
a2489d |
if(hostname)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
if(resolver)
|
|
Packit Service |
a2489d |
return(_("Resolving host address..."));
|
|
Packit Service |
a2489d |
if(!ReconnectAllowed())
|
|
Packit Service |
a2489d |
return DelayingMessage();
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
return "";
|
|
Packit Service |
a2489d |
case CONNECTING:
|
|
Packit Service |
a2489d |
return(_("Connecting..."));
|
|
Packit Service |
a2489d |
case CONNECTED:
|
|
Packit Service |
a2489d |
return(_("Connection idle"));
|
|
Packit Service |
a2489d |
case RECEIVING_HEADER:
|
|
Packit Service |
a2489d |
if(ModeIs(STORE) && !sent_eot && !status)
|
|
Packit Service |
a2489d |
return(_("Sending data"));
|
|
Packit Service |
a2489d |
if(tunnel_state==TUNNEL_WAITING)
|
|
Packit Service |
a2489d |
return(_("Connecting..."));
|
|
Packit Service |
a2489d |
if(!status)
|
|
Packit Service |
a2489d |
return(_("Waiting for response..."));
|
|
Packit Service |
a2489d |
return(_("Fetching headers..."));
|
|
Packit Service |
a2489d |
case RECEIVING_BODY:
|
|
Packit Service |
a2489d |
return(_("Receiving data"));
|
|
Packit Service |
a2489d |
case DONE:
|
|
Packit Service |
a2489d |
return "";
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
abort();
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
void Http::Reconfig(const char *name)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
const char *c=hostname;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
super::Reconfig(name);
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
no_cache = !QueryBool("cache",c);
|
|
Packit Service |
a2489d |
if(!hftp && NoProxy(hostname))
|
|
Packit Service |
a2489d |
SetProxy(0);
|
|
Packit Service |
a2489d |
else
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
const char *p=0;
|
|
Packit Service |
a2489d |
if(hftp && vproto && !strcmp(vproto,"ftp"))
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
p=ResMgr::Query("ftp:proxy",c);
|
|
Packit Service |
a2489d |
if(p && strncmp(p,"http://",7) && strncmp(p,"https://",8))
|
|
Packit Service |
a2489d |
p=0;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
if(!p)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
if(https)
|
|
Packit Service |
a2489d |
p=ResMgr::Query("https:proxy",c);
|
|
Packit Service |
a2489d |
else
|
|
Packit Service |
a2489d |
p=Query("proxy",c);
|
|
Packit Service |
a2489d |
// if no hftp:proxy is specified, try http:proxy.
|
|
Packit Service |
a2489d |
if(hftp && !p)
|
|
Packit Service |
a2489d |
p=ResMgr::Query("http:proxy",c);
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
SetProxy(p);
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
if(conn)
|
|
Packit Service |
a2489d |
SetSocketBuffer(conn->sock);
|
|
Packit Service |
a2489d |
if(proxy && proxy_port==0)
|
|
Packit Service |
a2489d |
proxy_port.set(HTTP_DEFAULT_PROXY_PORT);
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
user_agent=ResMgr::Query("http:user-agent",c);
|
|
Packit Service |
a2489d |
use_propfind_now=(use_propfind_now && QueryBool("use-propfind",c));
|
|
Packit Service |
a2489d |
no_ranges=(no_ranges || !QueryBool("use-range",hostname));
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
if(QueryBool("use-allprop",c)) {
|
|
Packit Service |
a2489d |
allprop.set( // PROPFIND request
|
|
Packit Service |
a2489d |
""
|
|
Packit Service |
a2489d |
"<propfind xmlns=\"DAV:\">"
|
|
Packit Service |
a2489d |
"<allprop/>"
|
|
Packit Service |
a2489d |
"</propfind>\r\n");
|
|
Packit Service |
a2489d |
} else {
|
|
Packit Service |
a2489d |
allprop.unset();
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
if(!user || !pass) {
|
|
Packit Service |
a2489d |
// get auth info from http:authorization setting
|
|
Packit Service |
a2489d |
const char *auth_c=Query("authorization",hostname);
|
|
Packit Service |
a2489d |
if(auth_c && *auth_c) {
|
|
Packit Service |
a2489d |
char *auth=alloca_strdup(auth_c);
|
|
Packit Service |
a2489d |
char *colon=strchr(auth,':');
|
|
Packit Service |
a2489d |
if(colon) {
|
|
Packit Service |
a2489d |
*colon=0;
|
|
Packit Service |
a2489d |
auth_user.set(auth);
|
|
Packit Service |
a2489d |
auth_pass.set(colon+1);
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
bool Http::SameSiteAs(const FileAccess *fa) const
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
if(!SameProtoAs(fa))
|
|
Packit Service |
a2489d |
return false;
|
|
Packit Service |
a2489d |
Http *o=(Http*)fa;
|
|
Packit Service |
a2489d |
return(!xstrcasecmp(hostname,o->hostname) && !xstrcmp(portname,o->portname)
|
|
Packit Service |
a2489d |
&& !xstrcmp(user,o->user) && !xstrcmp(pass,o->pass));
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
bool Http::SameLocationAs(const FileAccess *fa) const
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
if(!SameSiteAs(fa))
|
|
Packit Service |
a2489d |
return false;
|
|
Packit Service |
a2489d |
Http *o=(Http*)fa;
|
|
Packit Service |
a2489d |
if(cwd!=o->cwd)
|
|
Packit Service |
a2489d |
return false;
|
|
Packit Service |
a2489d |
return true;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
void Http::ResetLocationData()
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
super::ResetLocationData();
|
|
Packit Service |
a2489d |
Reconfig();
|
|
Packit Service |
a2489d |
state=DISCONNECTED;
|
|
Packit Service |
a2489d |
use_propfind_now=QueryBool("use-propfind",hostname);
|
|
Packit Service |
a2489d |
no_ranges=!QueryBool("use-range",hostname);
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
DirList *Http::MakeDirList(ArgV *args)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
return new HttpDirList(this,args);
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
#include "FileGlob.h"
|
|
Packit Service |
a2489d |
Glob *Http::MakeGlob(const char *pattern)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
return new GenericGlob(this,pattern);
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
ListInfo *Http::MakeListInfo(const char *path)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
return new HttpListInfo(this,path);
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
bool Http::CookieClosureMatch(const char *closure_c,
|
|
Packit Service |
a2489d |
const char *hostname,const char *efile)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
if(!closure_c)
|
|
Packit Service |
a2489d |
return true;
|
|
Packit Service |
a2489d |
char *closure=alloca_strdup2(closure_c,1);
|
|
Packit Service |
a2489d |
char *path=0;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
char *scan=closure;
|
|
Packit Service |
a2489d |
for(;;)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
char *slash=strchr(scan,';');
|
|
Packit Service |
a2489d |
if(!slash)
|
|
Packit Service |
a2489d |
break;
|
|
Packit Service |
a2489d |
*slash++=0;
|
|
Packit Service |
a2489d |
while(*slash && *slash==' ')
|
|
Packit Service |
a2489d |
slash++;
|
|
Packit Service |
a2489d |
if(!strncmp(slash,"path=",5))
|
|
Packit Service |
a2489d |
path=slash+5;
|
|
Packit Service |
a2489d |
else if(!strncmp(slash,"secure",6) && (slash[6]==';' || slash[6]==0))
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
if(!https)
|
|
Packit Service |
a2489d |
return false;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
if(closure[0] && 0!=fnmatch(closure,hostname,FNM_PATHNAME))
|
|
Packit Service |
a2489d |
return false;
|
|
Packit Service |
a2489d |
if(!path)
|
|
Packit Service |
a2489d |
return true;
|
|
Packit Service |
a2489d |
int path_len=strlen(path);
|
|
Packit Service |
a2489d |
if(path_len>0 && path[path_len-1]=='/')
|
|
Packit Service |
a2489d |
path_len--;
|
|
Packit Service |
a2489d |
if(!strncmp(efile,path,path_len)
|
|
Packit Service |
a2489d |
&& (efile[path_len]==0 || efile[path_len]=='/'))
|
|
Packit Service |
a2489d |
return true;
|
|
Packit Service |
a2489d |
return false;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
void Http::CookieMerge(xstring &all,const char *cookie_c)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
char *value=alloca_strdup(cookie_c);
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
for(char *entry=strtok(value,";"); entry; entry=strtok(0,";"))
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
if(*entry==' ')
|
|
Packit Service |
a2489d |
entry++;
|
|
Packit Service |
a2489d |
if(*entry==0)
|
|
Packit Service |
a2489d |
break;
|
|
Packit Service |
a2489d |
if(!strncasecmp(entry,"path=",5)
|
|
Packit Service |
a2489d |
|| !strncasecmp(entry,"expires=",8)
|
|
Packit Service |
a2489d |
|| !strncasecmp(entry,"domain=",7)
|
|
Packit Service |
a2489d |
|| (!strncasecmp(entry,"secure",6)
|
|
Packit Service |
a2489d |
&& (entry[6]==' ' || entry[6]==0 || entry[6]==';')))
|
|
Packit Service |
a2489d |
continue; // filter out path= expires= domain= secure
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
char *c_name=entry;
|
|
Packit Service |
a2489d |
char *c_value=strchr(entry,'=');
|
|
Packit Service |
a2489d |
if(c_value)
|
|
Packit Service |
a2489d |
*c_value++=0;
|
|
Packit Service |
a2489d |
else
|
|
Packit Service |
a2489d |
c_value=c_name, c_name=0;
|
|
Packit Service |
a2489d |
int c_name_len=xstrlen(c_name);
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
for(unsigned i=all.skip_all(0,' '); i
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
const char *scan=all+i;
|
|
Packit Service |
a2489d |
const char *semicolon=strchr(scan,';');
|
|
Packit Service |
a2489d |
const char *eq=strchr(scan,'=');
|
|
Packit Service |
a2489d |
if(semicolon && eq>semicolon)
|
|
Packit Service |
a2489d |
eq=0;
|
|
Packit Service |
a2489d |
if((eq==0 && c_name==0)
|
|
Packit Service |
a2489d |
|| (eq-scan==c_name_len && !strncmp(scan,c_name,c_name_len)))
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
// remove old cookie.
|
|
Packit Service |
a2489d |
if(!semicolon)
|
|
Packit Service |
a2489d |
all.truncate(i);
|
|
Packit Service |
a2489d |
else
|
|
Packit Service |
a2489d |
all.set_substr(i,all.skip_all(semicolon+1-all,' ')-i,"",0);
|
|
Packit Service |
a2489d |
break;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
if(!semicolon)
|
|
Packit Service |
a2489d |
break;
|
|
Packit Service |
a2489d |
i=semicolon+1-all;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
// append cookie.
|
|
Packit Service |
a2489d |
all.rtrim(' ');
|
|
Packit Service |
a2489d |
all.rtrim(';');
|
|
Packit Service |
a2489d |
int c_len=all.length();
|
|
Packit Service |
a2489d |
if(c_len>0 && all[c_len-1]!=';')
|
|
Packit Service |
a2489d |
all.append("; ");
|
|
Packit Service |
a2489d |
if(c_name)
|
|
Packit Service |
a2489d |
all.vappend(c_name,"=",c_value,NULL);
|
|
Packit Service |
a2489d |
else
|
|
Packit Service |
a2489d |
all.append(c_value);
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
void Http::MakeCookie(xstring &all_cookies,const char *hostname,const char *efile)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
Resource *scan=0;
|
|
Packit Service |
a2489d |
const char *closure;
|
|
Packit Service |
a2489d |
for(;;)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
const char *cookie=ResMgr::QueryNext("http:cookie",&closure,&scan;;
|
|
Packit Service |
a2489d |
if(cookie==0)
|
|
Packit Service |
a2489d |
break;
|
|
Packit Service |
a2489d |
if(!CookieClosureMatch(closure,hostname,efile))
|
|
Packit Service |
a2489d |
continue;
|
|
Packit Service |
a2489d |
CookieMerge(all_cookies,cookie);
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
void Http::SetCookie(const char *value_const)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
char *value=alloca_strdup(value_const);
|
|
Packit Service |
a2489d |
const char *domain=hostname;
|
|
Packit Service |
a2489d |
const char *path=0;
|
|
Packit Service |
a2489d |
bool secure=false;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
for(char *entry=strtok(value,";"); entry; entry=strtok(0,";"))
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
while(*entry==' ') // skip spaces.
|
|
Packit Service |
a2489d |
entry++;
|
|
Packit Service |
a2489d |
if(*entry==0)
|
|
Packit Service |
a2489d |
break;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
if(!strncasecmp(entry,"expires=",8))
|
|
Packit Service |
a2489d |
continue; // not used yet (FIXME)
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
if(!strncasecmp(entry,"secure",6)
|
|
Packit Service |
a2489d |
&& (entry[6]==' ' || entry[6]==0 || entry[6]==';'))
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
secure=true;
|
|
Packit Service |
a2489d |
continue;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
if(!strncasecmp(entry,"path=",5))
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
path=alloca_strdup(entry+5);
|
|
Packit Service |
a2489d |
continue;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
if(!strncasecmp(entry,"domain=",7))
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
char *new_domain=alloca_strdup(entry+6);
|
|
Packit Service |
a2489d |
if(new_domain[1]=='.')
|
|
Packit Service |
a2489d |
new_domain[0]='*';
|
|
Packit Service |
a2489d |
else
|
|
Packit Service |
a2489d |
new_domain++;
|
|
Packit Service |
a2489d |
char *end=strchr(new_domain,';');
|
|
Packit Service |
a2489d |
if(end)
|
|
Packit Service |
a2489d |
*end=0;
|
|
Packit Service |
a2489d |
domain=new_domain;
|
|
Packit Service |
a2489d |
continue;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
xstring closure(domain);
|
|
Packit Service |
a2489d |
if(path && path[0] && strcmp(path,"/"))
|
|
Packit Service |
a2489d |
closure.append(";path=").append(path);
|
|
Packit Service |
a2489d |
if(secure)
|
|
Packit Service |
a2489d |
closure.append(";secure");
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
xstring c(Query("cookie",closure));
|
|
Packit Service |
a2489d |
CookieMerge(c,value_const);
|
|
Packit Service |
a2489d |
ResMgr::Set("http:cookie",closure,c);
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
#if USE_SSL
|
|
Packit Service |
a2489d |
#undef super
|
|
Packit Service |
a2489d |
#define super Http
|
|
Packit Service |
a2489d |
Https::Https()
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
https=true;
|
|
Packit Service |
a2489d |
res_prefix="http";
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
Https::~Https()
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
Https::Https(const Https *o) : super(o)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
https=true;
|
|
Packit Service |
a2489d |
res_prefix="http";
|
|
Packit Service |
a2489d |
Reconfig(0);
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
FileAccess *Https::New(){ return new Https();}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
void Http::Connection::MakeSSLBuffers()
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
ssl=new lftp_ssl(sock,lftp_ssl::CLIENT,closure);
|
|
Packit Service |
a2489d |
ssl->load_keys();
|
|
Packit Service |
a2489d |
IOBufferSSL *send_buf_ssl=new IOBufferSSL(ssl,IOBuffer::PUT);
|
|
Packit Service |
a2489d |
IOBufferSSL *recv_buf_ssl=new IOBufferSSL(ssl,IOBuffer::GET);
|
|
Packit Service |
a2489d |
send_buf=send_buf_ssl;
|
|
Packit Service |
a2489d |
recv_buf=recv_buf_ssl;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
#endif
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
#undef super
|
|
Packit Service |
a2489d |
#define super Http
|
|
Packit Service |
a2489d |
HFtp::HFtp()
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
hftp=true;
|
|
Packit Service |
a2489d |
default_cwd="~";
|
|
Packit Service |
a2489d |
Reconfig(0);
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
HFtp::~HFtp()
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
HFtp::HFtp(const HFtp *o) : super(o)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
hftp=true;
|
|
Packit Service |
a2489d |
Reconfig(0);
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
void HFtp::Login(const char *u,const char *p)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
super::Login(u,p);
|
|
Packit Service |
a2489d |
if(u)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
home.Set("~");
|
|
Packit Service |
a2489d |
cwd.Set(home,false,0);
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
void HFtp::Reconfig(const char *name)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
super::Reconfig(name);
|
|
Packit Service |
a2489d |
use_head=QueryBool("use-head");
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
void Http::LogErrorText()
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
if(!conn || !conn->recv_buf)
|
|
Packit Service |
a2489d |
return;
|
|
Packit Service |
a2489d |
conn->recv_buf->Roll();
|
|
Packit Service |
a2489d |
int size=conn->recv_buf->Size();
|
|
Packit Service |
a2489d |
if(size==0)
|
|
Packit Service |
a2489d |
return;
|
|
Packit Service |
a2489d |
Buffer tmpbuf;
|
|
Packit Service |
a2489d |
size=_Read(&tmpbuf,size);
|
|
Packit Service |
a2489d |
if(size<=0)
|
|
Packit Service |
a2489d |
return;
|
|
Packit Service |
a2489d |
tmpbuf.SpaceAdd(size);
|
|
Packit Service |
a2489d |
const char *buf0=tmpbuf.Get();
|
|
Packit Service |
a2489d |
char *buf=alloca_strdup(buf0);
|
|
Packit Service |
a2489d |
remove_tags(buf);
|
|
Packit Service |
a2489d |
for(char *line=strtok(buf,"\n"); line; line=strtok(0,"\n")) {
|
|
Packit Service |
a2489d |
rtrim(line);
|
|
Packit Service |
a2489d |
if(*line)
|
|
Packit Service |
a2489d |
Log::global->Format(4,"<--* %s\n",line);
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
/* The functions http_atotm and check_end are taken from wget */
|
|
Packit Service |
a2489d |
#define ISSPACE(c) is_ascii_space((c))
|
|
Packit Service |
a2489d |
#define ISDIGIT(c) is_ascii_digit((c))
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
/* Check whether the result of strptime() indicates success.
|
|
Packit Service |
a2489d |
strptime() returns the pointer to how far it got to in the string.
|
|
Packit Service |
a2489d |
The processing has been successful if the string is at `GMT' or
|
|
Packit Service |
a2489d |
`+X', or at the end of the string.
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
In extended regexp parlance, the function returns 1 if P matches
|
|
Packit Service |
a2489d |
"^ *(GMT|[+-][0-9]|$)", 0 otherwise. P being NULL (a valid result of
|
|
Packit Service |
a2489d |
strptime()) is considered a failure and 0 is returned. */
|
|
Packit Service |
a2489d |
static int
|
|
Packit Service |
a2489d |
check_end (const char *p)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
if (!p)
|
|
Packit Service |
a2489d |
return 0;
|
|
Packit Service |
a2489d |
while (ISSPACE (*p))
|
|
Packit Service |
a2489d |
++p;
|
|
Packit Service |
a2489d |
if (!*p
|
|
Packit Service |
a2489d |
|| (p[0] == 'G' && p[1] == 'M' && p[2] == 'T')
|
|
Packit Service |
a2489d |
|| (p[0] == 'U' && p[1] == 'T' && p[2] == 'C')
|
|
Packit Service |
a2489d |
|| ((p[0] == '+' || p[1] == '-') && ISDIGIT (p[1])))
|
|
Packit Service |
a2489d |
return 1;
|
|
Packit Service |
a2489d |
else
|
|
Packit Service |
a2489d |
return 0;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
/* Convert TIME_STRING time to time_t. TIME_STRING can be in any of
|
|
Packit Service |
a2489d |
the three formats RFC2068 allows the HTTP servers to emit --
|
|
Packit Service |
a2489d |
RFC1123-date, RFC850-date or asctime-date. Timezones are ignored,
|
|
Packit Service |
a2489d |
and should be GMT.
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
We use strptime() to recognize various dates, which makes it a
|
|
Packit Service |
a2489d |
little bit slacker than the RFC1123/RFC850/asctime (e.g. it always
|
|
Packit Service |
a2489d |
allows shortened dates and months, one-digit days, etc.). It also
|
|
Packit Service |
a2489d |
allows more than one space anywhere where the specs require one SP.
|
|
Packit Service |
a2489d |
The routine should probably be even more forgiving (as recommended
|
|
Packit Service |
a2489d |
by RFC2068), but I do not have the time to write one.
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
Return the computed time_t representation, or ATOTM_ERROR if all the
|
|
Packit Service |
a2489d |
schemes fail.
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
Needless to say, what we *really* need here is something like
|
|
Packit Service |
a2489d |
Marcus Hennecke's atotm(), which is forgiving, fast, to-the-point,
|
|
Packit Service |
a2489d |
and does not use strptime(). atotm() is to be found in the sources
|
|
Packit Service |
a2489d |
of `phttpd', a little-known HTTP server written by Peter Erikson. */
|
|
Packit Service |
a2489d |
time_t
|
|
Packit Service |
a2489d |
Http::atotm (const char *time_string)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
struct tm t;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
/* Roger Beeman says: "This function dynamically allocates struct tm
|
|
Packit Service |
a2489d |
t, but does no initialization. The only field that actually
|
|
Packit Service |
a2489d |
needs initialization is tm_isdst, since the others will be set by
|
|
Packit Service |
a2489d |
strptime. Since strptime does not set tm_isdst, it will return
|
|
Packit Service |
a2489d |
the data structure with whatever data was in tm_isdst to begin
|
|
Packit Service |
a2489d |
with. For those of us in timezones where DST can occur, there
|
|
Packit Service |
a2489d |
can be a one hour shift depending on the previous contents of the
|
|
Packit Service |
a2489d |
data area where the data structure is allocated." */
|
|
Packit Service |
a2489d |
t.tm_isdst = -1;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
/* Note that under foreign locales Solaris strptime() fails to
|
|
Packit Service |
a2489d |
recognize English dates, which renders this function useless. I
|
|
Packit Service |
a2489d |
assume that other non-GNU strptime's are plagued by the same
|
|
Packit Service |
a2489d |
disease. We solve this by setting only LC_MESSAGES in
|
|
Packit Service |
a2489d |
i18n_initialize(), instead of LC_ALL.
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
Another solution could be to temporarily set locale to C, invoke
|
|
Packit Service |
a2489d |
strptime(), and restore it back. This is slow and dirty,
|
|
Packit Service |
a2489d |
however, and locale support other than LC_MESSAGES can mess other
|
|
Packit Service |
a2489d |
things, so I rather chose to stick with just setting LC_MESSAGES.
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
Also note that none of this is necessary under GNU strptime(),
|
|
Packit Service |
a2489d |
because it recognizes both international and local dates. */
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
/* NOTE: We don't use `%n' for white space, as OSF's strptime uses
|
|
Packit Service |
a2489d |
it to eat all white space up to (and including) a newline, and
|
|
Packit Service |
a2489d |
the function fails if there is no newline (!).
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
Let's hope all strptime() implementations use ` ' to skip *all*
|
|
Packit Service |
a2489d |
whitespace instead of just one (it works that way on all the
|
|
Packit Service |
a2489d |
systems I've tested it on). */
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
time_t ut=ATOTM_ERROR;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
setlocale(LC_TIME,"C"); // we need english month and week day names
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
/* RFC1123: Thu, 29 Jan 1998 22:12:57 */
|
|
Packit Service |
a2489d |
if (check_end (strptime (time_string, "%a, %d %b %Y %T", &t)))
|
|
Packit Service |
a2489d |
ut=mktime_from_utc (&t);
|
|
Packit Service |
a2489d |
/* RFC850: Thu, 29-Jan-98 22:12:57 */
|
|
Packit Service |
a2489d |
else if (check_end (strptime (time_string, "%a, %d-%b-%y %T", &t)))
|
|
Packit Service |
a2489d |
ut=mktime_from_utc (&t);
|
|
Packit Service |
a2489d |
/* asctime: Thu Jan 29 22:12:57 1998 */
|
|
Packit Service |
a2489d |
else if (check_end (strptime (time_string, "%a %b %d %T %Y", &t)))
|
|
Packit Service |
a2489d |
ut=mktime_from_utc (&t);
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
setlocale(LC_TIME,""); // restore locale
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
return ut;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
bool Http::IsCompressed(const char *s)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
static const char *const values[] = {
|
|
Packit Service |
a2489d |
"x-gzip", "gzip", "deflate", "compress", "x-compress", NULL
|
|
Packit Service |
a2489d |
};
|
|
Packit Service |
a2489d |
for(const char *const *v=values; *v; v++)
|
|
Packit Service |
a2489d |
if(!strcmp(s,*v))
|
|
Packit Service |
a2489d |
return true;
|
|
Packit Service |
a2489d |
return false;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
bool Http::CompressedContentEncoding() const
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
return content_encoding && IsCompressed(content_encoding);
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
bool Http::CompressedContentType() const
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
if(file.ends_with(".gz") || file.ends_with(".Z") || file.ends_with(".tgz"))
|
|
Packit Service |
a2489d |
return true;
|
|
Packit Service |
a2489d |
static const char app[]="application/";
|
|
Packit Service |
a2489d |
return entity_content_type && entity_content_type.begins_with(app)
|
|
Packit Service |
a2489d |
&& IsCompressed(entity_content_type+sizeof(app)-1);
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
#include "modconfig.h"
|
|
Packit Service |
a2489d |
#ifdef MODULE_PROTO_HTTP
|
|
Packit Service |
a2489d |
void module_init()
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
Http::ClassInit();
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
#endif
|