1 /*
2  *  Copyright (C) 2005-2018 Team Kodi
3  *  This file is part of Kodi - https://kodi.tv
4  *
5  *  SPDX-License-Identifier: GPL-2.0-or-later
6  *  See LICENSES/README.md for more information.
7  */
8 
9 #pragma once
10 
11 #include "IFile.h"
12 #include "utils/HttpHeader.h"
13 #include "utils/RingBuffer.h"
14 
15 #include <map>
16 #include <string>
17 
18 typedef void CURL_HANDLE;
19 typedef void CURLM;
20 struct curl_slist;
21 
22 namespace XFILE
23 {
24   class CCurlFile : public IFile
25   {
26     private:
27       typedef enum
28       {
29         PROXY_HTTP = 0,
30         PROXY_SOCKS4,
31         PROXY_SOCKS4A,
32         PROXY_SOCKS5,
33         PROXY_SOCKS5_REMOTE,
34       } ProxyType;
35 
36     public:
37       CCurlFile();
38       ~CCurlFile() override;
39       bool Open(const CURL& url) override;
40       bool OpenForWrite(const CURL& url, bool bOverWrite = false) override;
41       bool ReOpen(const CURL& url) override;
42       bool Exists(const CURL& url) override;
43       int64_t Seek(int64_t iFilePosition, int iWhence=SEEK_SET) override;
44       int64_t GetPosition() override;
45       int64_t GetLength() override;
46       int Stat(const CURL& url, struct __stat64* buffer) override;
47       void Close() override;
ReadString(char * szLine,int iLineLength)48       bool ReadString(char *szLine, int iLineLength) override { return m_state->ReadString(szLine, iLineLength); }
Read(void * lpBuf,size_t uiBufSize)49       ssize_t Read(void* lpBuf, size_t uiBufSize) override { return m_state->Read(lpBuf, uiBufSize); }
50       ssize_t Write(const void* lpBuf, size_t uiBufSize) override;
51       const std::string GetProperty(XFILE::FileProperty type, const std::string &name = "") const override;
52       const std::vector<std::string> GetPropertyValues(XFILE::FileProperty type, const std::string &name = "") const override;
53       int IoControl(EIoControl request, void* param) override;
54       double GetDownloadSpeed() override;
55 
56       bool Post(const std::string& strURL, const std::string& strPostData, std::string& strHTML);
57       bool Get(const std::string& strURL, std::string& strHTML);
58       bool ReadData(std::string& strHTML);
59       bool Download(const std::string& strURL, const std::string& strFileName, unsigned int* pdwSize = NULL);
60       bool IsInternet();
61       void Cancel();
62       void Reset();
SetUserAgent(const std::string & sUserAgent)63       void SetUserAgent(const std::string& sUserAgent) { m_userAgent = sUserAgent; }
64       void SetProxy(const std::string &type, const std::string &host, uint16_t port,
65                     const std::string &user, const std::string &password);
SetCustomRequest(const std::string & request)66       void SetCustomRequest(const std::string &request) { m_customrequest = request; }
SetAcceptEncoding(const std::string & encoding)67       void SetAcceptEncoding(const std::string& encoding) { m_acceptencoding = encoding; }
SetAcceptCharset(const std::string & charset)68       void SetAcceptCharset(const std::string& charset) { m_acceptCharset = charset; }
SetTimeout(int connecttimeout)69       void SetTimeout(int connecttimeout) { m_connecttimeout = connecttimeout; }
SetLowSpeedTime(int lowspeedtime)70       void SetLowSpeedTime(int lowspeedtime) { m_lowspeedtime = lowspeedtime; }
SetPostData(const std::string & postdata)71       void SetPostData(const std::string& postdata) { m_postdata = postdata; }
SetReferer(const std::string & referer)72       void SetReferer(const std::string& referer) { m_referer = referer; }
SetCookie(const std::string & cookie)73       void SetCookie(const std::string& cookie) { m_cookie = cookie; }
SetMimeType(const std::string & mimetype)74       void SetMimeType(const std::string& mimetype) { SetRequestHeader("Content-Type", mimetype); }
75       void SetRequestHeader(const std::string& header, const std::string& value);
76       void SetRequestHeader(const std::string& header, long value);
77 
78       void ClearRequestHeaders();
79       void SetBufferSize(unsigned int size);
80 
GetHttpHeader()81       const CHttpHeader& GetHttpHeader() const { return m_state->m_httpheader; }
82       std::string GetURL(void);
83       std::string GetRedirectURL();
84 
85       /* static function that will get content type of a file */
86       static bool GetHttpHeader(const CURL &url, CHttpHeader &headers);
87       static bool GetMimeType(const CURL &url, std::string &content, const std::string &useragent="");
88       static bool GetContentType(const CURL &url, std::string &content, const std::string &useragent = "");
89 
90       /* static function that will get cookies stored by CURL in RFC 2109 format */
91       static bool GetCookies(const CURL &url, std::string &cookies);
92 
93       class CReadState
94       {
95       public:
96           CReadState();
97           ~CReadState();
98           CURL_HANDLE* m_easyHandle;
99           CURLM* m_multiHandle;
100 
101           CRingBuffer m_buffer; // our ringhold buffer
102           unsigned int m_bufferSize;
103 
104           char* m_overflowBuffer; // in the rare case we would overflow the above buffer
105           unsigned int m_overflowSize; // size of the overflow buffer
106           int m_stillRunning; // Is background url fetch still in progress
107           bool m_cancelled;
108           int64_t m_fileSize;
109           int64_t m_filePos;
110           bool m_bFirstLoop;
111           bool m_isPaused;
112           bool m_sendRange;
113           bool m_bLastError;
114           bool m_bRetry;
115 
116           char* m_readBuffer;
117 
118           /* returned http header */
119           CHttpHeader m_httpheader;
IsHeaderDone(void)120           bool IsHeaderDone(void) { return m_httpheader.IsHeaderDone(); }
121 
122           curl_slist* m_curlHeaderList;
123           curl_slist* m_curlAliasList;
124 
125           size_t ReadCallback(char *buffer, size_t size, size_t nitems);
126           size_t WriteCallback(char *buffer, size_t size, size_t nitems);
127           size_t HeaderCallback(void *ptr, size_t size, size_t nmemb);
128 
129           bool Seek(int64_t pos);
130           ssize_t Read(void* lpBuf, size_t uiBufSize);
131           bool ReadString(char *szLine, int iLineLength);
132           int8_t FillBuffer(unsigned int want);
133           void SetReadBuffer(const void* lpBuf, int64_t uiBufSize);
134 
135           void SetResume(void);
136           long Connect(unsigned int size);
137           void Disconnect();
138       };
139 
140     protected:
141       void ParseAndCorrectUrl(CURL &url);
142       void SetCommonOptions(CReadState* state, bool failOnError = true);
143       void SetRequestHeaders(CReadState* state);
144       void SetCorrectHeaders(CReadState* state);
145       bool Service(const std::string& strURL, std::string& strHTML);
146       std::string GetInfoString(int infoType);
147 
148     protected:
149       CReadState* m_state;
150       CReadState* m_oldState;
151       unsigned int m_bufferSize;
152       int64_t m_writeOffset = 0;
153 
154       std::string m_url;
155       std::string m_userAgent;
156       ProxyType m_proxytype = PROXY_HTTP;
157       std::string m_proxyhost;
158       uint16_t m_proxyport = 3128;
159       std::string m_proxyuser;
160       std::string m_proxypassword;
161       std::string m_customrequest;
162       std::string m_acceptencoding;
163       std::string m_acceptCharset;
164       std::string m_ftpauth;
165       std::string m_ftpport;
166       std::string m_binary;
167       std::string m_postdata;
168       std::string m_referer;
169       std::string m_cookie;
170       std::string m_username;
171       std::string m_password;
172       std::string m_httpauth;
173       std::string m_cipherlist;
174       bool m_ftppasvip;
175       int m_connecttimeout;
176       int m_redirectlimit;
177       int m_lowspeedtime;
178       bool m_opened;
179       bool m_forWrite;
180       bool m_inError;
181       bool m_seekable;
182       bool m_multisession;
183       bool m_skipshout;
184       bool m_postdataset;
185       bool m_allowRetry;
186       bool m_verifyPeer = true;
187       bool m_failOnError = true;
188       curl_slist* m_dnsCacheList = nullptr;
189 
190       CRingBuffer m_buffer; // our ringhold buffer
191       char* m_overflowBuffer; // in the rare case we would overflow the above buffer
192       unsigned int m_overflowSize = 0; // size of the overflow buffer
193 
194       int  m_stillRunning; // Is background url fetch still in progress?
195 
196       typedef std::map<std::string, std::string> MAPHTTPHEADERS;
197       MAPHTTPHEADERS m_requestheaders;
198 
199       long m_httpresponse;
200   };
201 }
202