1 /* 2 SPDX-FileCopyrightText: 2000, 2001 Dawit Alemayehu <adawit@kde.org> 3 SPDX-FileCopyrightText: 2000, 2001 Waldo Bastian <bastian@kde.org> 4 SPDX-FileCopyrightText: 2000, 2001 George Staikos <staikos@kde.org> 5 SPDX-FileCopyrightText: 2001, 2002 Hamish Rodda <rodda@kde.org> 6 SPDX-FileCopyrightText: 2007 Daniel Nicoletti <mirttex@users.sourceforge.net> 7 SPDX-FileCopyrightText: 2008, 2009 Andreas Hartmetz <ahartmetz@gmail.com> 8 9 SPDX-License-Identifier: LGPL-2.0-or-later 10 */ 11 12 #ifndef HTTP_H 13 #define HTTP_H 14 15 #include <QDateTime> 16 #include <QList> 17 #include <QLocalSocket> 18 #include <QStringList> 19 #include <QUrl> 20 21 #include "httpmethod_p.h" 22 #include "kio/tcpslavebase.h" 23 24 class QDomNodeList; 25 class QFile; 26 class QIODevice; 27 class QNetworkConfigurationManager; 28 namespace KIO 29 { 30 class AuthInfo; 31 } 32 33 class HeaderTokenizer; 34 class KAbstractHttpAuthentication; 35 36 class HTTPProtocol : public QObject, public KIO::TCPSlaveBase 37 { 38 Q_OBJECT 39 public: 40 HTTPProtocol(const QByteArray &protocol, const QByteArray &pool, const QByteArray &app); 41 ~HTTPProtocol() override; 42 43 /** HTTP version **/ 44 enum HTTP_REV { HTTP_None, HTTP_Unknown, HTTP_10, HTTP_11, SHOUTCAST }; 45 46 /** Authorization method used **/ 47 enum AUTH_SCHEME { AUTH_None, AUTH_Basic, AUTH_NTLM, AUTH_Digest, AUTH_Negotiate }; 48 49 /** DAV-specific request elements for the current connection **/ 50 struct DAVRequest { DAVRequestDAVRequest51 DAVRequest() 52 { 53 overwrite = false; 54 depth = 0; 55 } 56 57 QString desturl; 58 bool overwrite; 59 int depth; 60 }; 61 62 enum CacheIOMode { 63 NoCache = 0, 64 ReadFromCache = 1, 65 WriteToCache = 2, 66 }; 67 68 struct CacheTag { CacheTagCacheTag69 CacheTag() 70 { 71 useCache = false; 72 ioMode = NoCache; 73 bytesCached = 0; 74 file = nullptr; 75 } 76 77 enum CachePlan { 78 UseCached = 0, 79 ValidateCached, 80 IgnoreCached, 81 }; 82 // int maxCacheAge refers to seconds 83 CachePlan plan(int maxCacheAge) const; 84 85 QByteArray serialize() const; 86 bool deserialize(const QByteArray &); 87 88 KIO::CacheControl policy; // ### initialize in the constructor? 89 bool useCache; // Whether the cache should be used 90 enum CacheIOMode ioMode; // Write to cache file, read from it, or don't use it. 91 quint32 fileUseCount; 92 quint32 bytesCached; 93 QString etag; // entity tag header as described in the HTTP standard. 94 QFile *file; // file on disk - either a QTemporaryFile (write) or QFile (read) 95 QDateTime servedDate; // Date when the resource was served by the origin server 96 QDateTime lastModifiedDate; // Last modified. 97 QDateTime expireDate; // Date when the cache entry will expire 98 QString charset; 99 }; 100 101 /** The request for the current connection **/ 102 struct HTTPRequest { HTTPRequestHTTPRequest103 HTTPRequest() 104 { 105 method = KIO::HTTP_UNKNOWN; 106 offset = 0; 107 endoffset = 0; 108 allowTransferCompression = false; 109 disablePassDialog = false; 110 doNotWWWAuthenticate = false; 111 doNotProxyAuthenticate = false; 112 preferErrorPage = false; 113 useCookieJar = false; 114 } 115 116 QByteArray methodString() const; 117 118 QUrl url; 119 QString encoded_hostname; //### can be calculated on-the-fly 120 // Persistent connections 121 bool isKeepAlive; 122 int keepAliveTimeout; // Timeout in seconds. 123 124 KIO::HTTP_METHOD method; 125 QString methodStringOverride; // Overrides method if non-empty. 126 QByteArray sentMethodString; // Stores http method actually sent 127 KIO::filesize_t offset; 128 KIO::filesize_t endoffset; 129 QString windowId; // Window Id this request is related to. 130 // Header fields 131 QString referrer; 132 QString charsets; 133 QString languages; 134 QString userAgent; 135 // Previous and current response codes 136 unsigned int responseCode; 137 unsigned int prevResponseCode; 138 // Miscellaneous 139 QString id; 140 DAVRequest davData; 141 QUrl redirectUrl; 142 QUrl proxyUrl; 143 QStringList proxyUrls; 144 145 bool isPersistentProxyConnection; 146 bool allowTransferCompression; 147 bool disablePassDialog; 148 bool doNotWWWAuthenticate; 149 bool doNotProxyAuthenticate; 150 // Indicates whether an error page or error message is preferred. 151 bool preferErrorPage; 152 153 // Use the cookie jar (or pass cookies to the application as metadata instead) 154 bool useCookieJar; 155 // Cookie flags 156 enum { CookiesAuto, CookiesManual, CookiesNone } cookieMode; 157 158 CacheTag cacheTag; 159 }; 160 161 /** State of the current connection to the server **/ 162 struct HTTPServerState { HTTPServerStateHTTPServerState163 HTTPServerState() 164 { 165 isKeepAlive = false; 166 isPersistentProxyConnection = false; 167 } 168 initFromHTTPServerState169 void initFrom(const HTTPRequest &request) 170 { 171 url = request.url; 172 encoded_hostname = request.encoded_hostname; 173 isKeepAlive = request.isKeepAlive; 174 proxyUrl = request.proxyUrl; 175 isPersistentProxyConnection = request.isPersistentProxyConnection; 176 } 177 updateCredentialsHTTPServerState178 void updateCredentials(const HTTPRequest &request) 179 { 180 if (url.host() == request.url.host() && url.port() == request.url.port()) { 181 url.setUserName(request.url.userName()); 182 url.setPassword(request.url.password()); 183 } 184 if (proxyUrl.host() == request.proxyUrl.host() && proxyUrl.port() == request.proxyUrl.port()) { 185 proxyUrl.setUserName(request.proxyUrl.userName()); 186 proxyUrl.setPassword(request.proxyUrl.password()); 187 } 188 } 189 clearHTTPServerState190 void clear() 191 { 192 url.clear(); 193 encoded_hostname.clear(); 194 proxyUrl.clear(); 195 isKeepAlive = false; 196 isPersistentProxyConnection = false; 197 } 198 199 QUrl url; 200 QString encoded_hostname; 201 QUrl proxyUrl; 202 bool isKeepAlive; 203 bool isPersistentProxyConnection; 204 }; 205 206 //---------------------- Re-implemented methods ---------------- 207 virtual void setHost(const QString &host, quint16 port, const QString &user, const QString &pass) override; 208 209 void slave_status() override; 210 211 void get(const QUrl &url) override; 212 void put(const QUrl &url, int _mode, KIO::JobFlags flags) override; 213 214 //----------------- Re-implemented methods for WebDAV ----------- 215 void listDir(const QUrl &url) override; 216 void mkdir(const QUrl &url, int _permissions) override; 217 218 void rename(const QUrl &src, const QUrl &dest, KIO::JobFlags flags) override; 219 void copy(const QUrl &src, const QUrl &dest, int _permissions, KIO::JobFlags flags) override; 220 void del(const QUrl &url, bool _isfile) override; 221 222 // ask the host whether it supports WebDAV & cache this info 223 bool davHostOk(); 224 225 // send generic DAV request 226 void davGeneric(const QUrl &url, KIO::HTTP_METHOD method, qint64 size = -1); 227 228 // Send requests to lock and unlock resources 229 void davLock(const QUrl &url, const QString &scope, const QString &type, const QString &owner); 230 void davUnlock(const QUrl &url); 231 232 // Calls httpClose() and finished() 233 void davFinished(); 234 235 // Handle error conditions 236 QString davError(int code = -1, const QString &url = QString()); 237 //---------------------------- End WebDAV ----------------------- 238 239 /** 240 * Special commands supported by this slave : 241 * 1 - HTTP POST 242 * 2 - Cache has been updated 243 * 3 - SSL Certificate Cache has been updated 244 * 4 - HTTP multi get 245 * 5 - DAV LOCK (see 246 * 6 - DAV UNLOCK README.webdav) 247 */ 248 void special(const QByteArray &data) override; 249 250 void mimetype(const QUrl &url) override; 251 252 void stat(const QUrl &url) override; 253 254 void reparseConfiguration() override; 255 256 /** 257 * Forced close of connection 258 */ 259 void closeConnection() override; 260 261 void post(const QUrl &url, qint64 size = -1); 262 void multiGet(const QByteArray &data) override; 263 bool maybeSetRequestUrl(const QUrl &); 264 265 /** 266 * Generate and send error message based on response code. 267 */ 268 bool sendHttpError(); 269 270 /** 271 * Call SlaveBase::errorPage() and remember that we've called it 272 */ 273 bool sendErrorPageNotification(); 274 275 /** 276 * Check network status 277 */ 278 bool isOffline(); 279 280 protected Q_SLOTS: 281 void slotData(const QByteArray &); 282 void slotFilterError(const QString &text); 283 void error(int errid, const QString &text); 284 void proxyAuthenticationForSocket(const QNetworkProxy &, QAuthenticator *); 285 void saveProxyAuthenticationForSocket(); 286 287 protected: 288 int readChunked(); ///< Read a chunk 289 int readLimited(); ///< Read maximum m_iSize bytes. 290 int readUnlimited(); ///< Read as much as possible. 291 292 /** 293 * A thin wrapper around TCPSlaveBase::write() that will retry writing as 294 * long as no error occurs. 295 */ 296 ssize_t write(const void *buf, size_t nbytes); 297 using SlaveBase::write; 298 299 /** 300 * Add an encoding on to the appropriate stack this 301 * is necessary because transfer encodings and 302 * content encodings must be handled separately. 303 */ 304 void addEncoding(const QString &, QStringList &); 305 306 quint16 defaultPort() const; 307 308 // The methods between here and sendQuery() are helpers for sendQuery(). 309 310 /** 311 * Return true if the request is already "done", false otherwise. 312 * 313 * @p cacheHasPage will be set to true if the page was found, false otherwise. 314 */ 315 bool satisfyRequestFromCache(bool *cacheHasPage); 316 QString formatRequestUri() const; 317 /** 318 * create HTTP authentications response(s), if any 319 */ 320 QString authenticationHeader(); 321 bool sendQuery(); 322 323 /** 324 * Close transfer 325 */ 326 void httpClose(bool keepAlive); 327 /** 328 * Open connection 329 */ 330 bool httpOpenConnection(); 331 /** 332 * Close connection 333 */ 334 void httpCloseConnection(); 335 /** 336 * Check whether to keep or close the connection. 337 */ 338 bool httpShouldCloseConnection(); 339 340 void forwardHttpResponseHeader(bool forwardImmediately = true); 341 342 /** 343 * fix common MIME type errors by webservers. 344 * 345 * Helper for readResponseHeader(). 346 */ 347 void fixupResponseMimetype(); 348 /** 349 * fix common content-encoding errors by webservers. 350 * 351 * Helper for readResponseHeader(). 352 */ 353 void fixupResponseContentEncoding(); 354 355 bool readResponseHeader(); 356 bool parseHeaderFromCache(); 357 void parseContentDisposition(const QString &disposition); 358 359 bool sendBody(); 360 bool sendCachedBody(); 361 362 // where dataInternal == true, the content is to be made available 363 // to an internal function. 364 bool readBody(bool dataInternal = false); 365 366 /** 367 * Performs a WebDAV stat or list 368 */ 369 void davSetRequest(const QByteArray &requestXML); 370 void davStatList(const QUrl &url, bool stat = true); 371 void davParsePropstats(const QDomNodeList &propstats, KIO::UDSEntry &entry); 372 void davParseActiveLocks(const QDomNodeList &activeLocks, uint &lockCount); 373 374 /** 375 * Parses a date & time string 376 */ 377 QDateTime parseDateTime(const QString &input, const QString &type); 378 379 /** 380 * Returns the error code from a "HTTP/1.1 code Code Name" string 381 */ 382 int codeFromResponse(const QString &response); 383 384 /** 385 * Extracts locks from metadata 386 * Returns the appropriate If: header 387 */ 388 QString davProcessLocks(); 389 390 /** 391 * Send a cookie to the cookiejar 392 */ 393 void addCookies(const QString &url, const QByteArray &cookieHeader); 394 395 /** 396 * Look for cookies in the cookiejar 397 */ 398 QString findCookies(const QString &url); 399 400 void cacheParseResponseHeader(const HeaderTokenizer &tokenizer); 401 402 QString cacheFilePathFromUrl(const QUrl &url) const; 403 bool cacheFileOpenRead(); 404 bool cacheFileOpenWrite(); 405 void cacheFileClose(); 406 void sendCacheCleanerCommand(const QByteArray &command); 407 408 QByteArray cacheFileReadPayload(int maxLength); 409 void cacheFileWritePayload(const QByteArray &d); 410 void cacheFileWriteTextHeader(); 411 /** 412 * check URL to guard against hash collisions, and load the etag for validation 413 */ 414 bool cacheFileReadTextHeader1(const QUrl &desiredUrl); 415 /** 416 * load the rest of the text fields 417 */ 418 bool cacheFileReadTextHeader2(); 419 void setCacheabilityMetadata(bool cachingAllowed); 420 421 /** 422 * Do everything proceedUntilResponseHeader does, and also get the response body. 423 * This is being used as a replacement for proceedUntilResponseHeader() in 424 * situations where we actually expect the response to have a body / payload data. 425 * 426 * where dataInternal == true, the content is to be made available 427 * to an internal function. 428 */ 429 void proceedUntilResponseContent(bool dataInternal = false); 430 431 /** 432 * Ensure we are connected, send our query, and get the response header. 433 */ 434 bool proceedUntilResponseHeader(); 435 436 /** 437 * Resets any per session settings. 438 */ 439 void resetSessionSettings(); 440 441 /** 442 * Resets variables related to parsing a response. 443 */ 444 void resetResponseParsing(); 445 446 /** 447 * Resets any per connection settings. These are different from 448 * per-session settings in that they must be invalidated every time 449 * a request is made, e.g. a retry to re-send the header to the 450 * server, as compared to only when a new request arrives. 451 */ 452 void resetConnectionSettings(); 453 454 /** 455 * Caches the POST data in a temporary buffer. 456 * 457 * Depending on size of content, the temporary buffer might be 458 * created either in memory or on disk as (a temporary file). 459 */ 460 void cachePostData(const QByteArray &); 461 462 /** 463 * Clears the POST data buffer. 464 * 465 * Note that calling this function results in the POST data buffer 466 * getting completely deleted. 467 */ 468 void clearPostDataBuffer(); 469 470 /** 471 * Returns true on successful retrieval of all content data. 472 */ 473 bool retrieveAllData(); 474 475 /** 476 * Saves HTTP authentication data. 477 */ 478 void saveAuthenticationData(); 479 480 /** 481 * Handles HTTP authentication. 482 */ 483 bool handleAuthenticationHeader(const HeaderTokenizer *tokenizer); 484 485 /** 486 * Handles file -> webdav put requests. 487 */ 488 void copyPut(const QUrl &src, const QUrl &dest, KIO::JobFlags flags); 489 490 /** 491 * Stats a remote DAV file and returns true if it already exists. 492 */ 493 bool davDestinationExists(); 494 495 void virtual_hook(int id, void *data) override; 496 497 private: 498 void fileSystemFreeSpace(const QUrl &url); // KF6 TODO: Once a virtual fileSystemFreeSpace method in SlaveBase exists, override it 499 500 protected: 501 /* This stores information about the credentials already tried 502 * during the authentication stage (in case the auth method uses 503 * a username and password). Initially the job-provided credentials 504 * are used (if any). In case of failure the credential cache is 505 * queried and if this fails the user is asked to provide credentials 506 * interactively (unless forbidden by metadata) */ 507 enum TriedCredentials { 508 NoCredentials = 0, 509 JobCredentials, 510 CachedCredentials, 511 UserInputCredentials, 512 }; 513 514 HTTPServerState m_server; 515 HTTPRequest m_request; 516 QList<HTTPRequest> m_requestQueue; 517 518 // Processing related 519 KIO::filesize_t m_iSize; ///< Expected size of message 520 KIO::filesize_t m_iPostDataSize; 521 KIO::filesize_t m_iBytesLeft; ///< # of bytes left to receive in this message. 522 KIO::filesize_t m_iContentLeft; ///< # of content bytes left 523 QByteArray m_receiveBuf; ///< Receive buffer 524 bool m_dataInternal; ///< Data is for internal consumption 525 bool m_isChunked; ///< Chunked transfer encoding 526 527 bool m_isBusy; ///< Busy handling request queue. 528 bool m_isEOF; 529 bool m_isEOD; 530 531 //--- Settings related to a single response only 532 bool m_isRedirection; ///< Indicates current request is a redirection 533 QStringList m_responseHeaders; ///< All headers 534 535 // Language/Encoding related 536 QStringList m_transferEncodings; 537 QStringList m_contentEncodings; 538 QString m_contentMD5; 539 QString m_mimeType; // TODO QByteArray? 540 541 //--- WebDAV 542 // Data structure to hold data which will be passed to an internal func. 543 QByteArray m_webDavDataBuf; 544 QStringList m_davCapabilities; 545 546 bool m_davHostOk; 547 bool m_davHostUnsupported; 548 //---------- 549 550 // Mimetype determination 551 bool m_cpMimeBuffer; 552 QByteArray m_mimeTypeBuffer; 553 554 // Holds the POST data so it won't get lost on if we 555 // happened to get a 401/407 response when submitting 556 // a form. 557 QIODevice *m_POSTbuf; 558 559 // Cache related 560 int m_maxCacheAge; ///< Maximum age of a cache entry in seconds. 561 long m_maxCacheSize; ///< Maximum cache size in Kb. 562 QString m_strCacheDir; ///< Location of the cache. 563 QLocalSocket m_cacheCleanerConnection; ///< Connection to the cache cleaner process 564 565 // Operation mode 566 QByteArray m_protocol; 567 568 KAbstractHttpAuthentication *m_wwwAuth; 569 QList<QByteArray> m_blacklistedWwwAuthMethods; 570 TriedCredentials m_triedWwwCredentials; 571 KAbstractHttpAuthentication *m_proxyAuth; 572 QList<QByteArray> m_blacklistedProxyAuthMethods; 573 TriedCredentials m_triedProxyCredentials; 574 // For proxy auth when it's handled by the Qt/KDE socket classes 575 QAuthenticator *m_socketProxyAuth; 576 577 // To know if we are online or not 578 QNetworkConfigurationManager *m_networkConfig; 579 // The current KIO error on this request / response pair - zero / KJob::NoError if no error 580 int m_kioError; 581 // Whether we are loading an error page (body of a reply with error response code) 582 bool m_isLoadingErrorPage; 583 584 // Values that determine the remote connection timeouts. 585 int m_remoteRespTimeout; 586 587 // EOF Retry count 588 quint8 m_iEOFRetryCount; 589 590 QByteArray m_unreadBuf; 591 void clearUnreadBuffer(); 592 void unread(char *buf, size_t size); 593 size_t readBuffered(char *buf, size_t size, bool unlimited = true); 594 bool readDelimitedText(char *buf, int *idx, int end, int numNewlines); 595 }; 596 #endif 597