
Bug: webrtc:6424 Change-Id: I191d8d6a0bb88b6cfbfc95015386c4451000d2c6 Reviewed-on: https://webrtc-review.googlesource.com/100800 Reviewed-by: Karl Wiberg <kwiberg@webrtc.org> Commit-Queue: Niels Moller <nisse@webrtc.org> Cr-Commit-Position: refs/heads/master@{#24794}
299 lines
9.6 KiB
C++
299 lines
9.6 KiB
C++
/*
|
|
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
|
|
*
|
|
* Use of this source code is governed by a BSD-style license
|
|
* that can be found in the LICENSE file in the root of the source
|
|
* tree. An additional intellectual property rights grant can be found
|
|
* in the file PATENTS. All contributing project authors may
|
|
* be found in the AUTHORS file in the root of the source tree.
|
|
*/
|
|
|
|
#ifndef RTC_BASE_HTTPCOMMON_H_
|
|
#define RTC_BASE_HTTPCOMMON_H_
|
|
|
|
#include <map>
|
|
#include <memory>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include "rtc_base/checks.h"
|
|
#include "rtc_base/stream.h"
|
|
#include "rtc_base/stringutils.h"
|
|
|
|
namespace rtc {
|
|
|
|
class CryptString;
|
|
class SocketAddress;
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Constants
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
enum HttpCode {
|
|
HC_OK = 200,
|
|
HC_INTERNAL_SERVER_ERROR = 500,
|
|
};
|
|
|
|
enum HttpVersion { HVER_1_0, HVER_1_1, HVER_UNKNOWN, HVER_LAST = HVER_UNKNOWN };
|
|
|
|
enum HttpError {
|
|
HE_NONE,
|
|
HE_PROTOCOL, // Received non-valid HTTP data
|
|
HE_DISCONNECTED, // Connection closed unexpectedly
|
|
HE_OVERFLOW, // Received too much data for internal buffers
|
|
HE_CONNECT_FAILED, // The socket failed to connect.
|
|
HE_SOCKET_ERROR, // An error occurred on a connected socket
|
|
HE_SHUTDOWN, // Http object is being destroyed
|
|
HE_OPERATION_CANCELLED, // Connection aborted locally
|
|
HE_AUTH, // Proxy Authentication Required
|
|
HE_CERTIFICATE_EXPIRED, // During SSL negotiation
|
|
HE_STREAM, // Problem reading or writing to the document
|
|
HE_CACHE, // Problem reading from cache
|
|
HE_DEFAULT
|
|
};
|
|
|
|
enum HttpHeader {
|
|
HH_AGE,
|
|
HH_CACHE_CONTROL,
|
|
HH_CONNECTION,
|
|
HH_CONTENT_DISPOSITION,
|
|
HH_CONTENT_LENGTH,
|
|
HH_CONTENT_RANGE,
|
|
HH_CONTENT_TYPE,
|
|
HH_COOKIE,
|
|
HH_DATE,
|
|
HH_ETAG,
|
|
HH_EXPIRES,
|
|
HH_HOST,
|
|
HH_IF_MODIFIED_SINCE,
|
|
HH_IF_NONE_MATCH,
|
|
HH_KEEP_ALIVE,
|
|
HH_LAST_MODIFIED,
|
|
HH_LOCATION,
|
|
HH_PROXY_AUTHENTICATE,
|
|
HH_PROXY_AUTHORIZATION,
|
|
HH_PROXY_CONNECTION,
|
|
HH_RANGE,
|
|
HH_SET_COOKIE,
|
|
HH_TE,
|
|
HH_TRAILERS,
|
|
HH_TRANSFER_ENCODING,
|
|
HH_UPGRADE,
|
|
HH_USER_AGENT,
|
|
HH_WWW_AUTHENTICATE,
|
|
HH_LAST = HH_WWW_AUTHENTICATE
|
|
};
|
|
|
|
const uint16_t HTTP_DEFAULT_PORT = 80;
|
|
const uint16_t HTTP_SECURE_PORT = 443;
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Utility Functions
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
const char* ToString(HttpVersion version);
|
|
bool FromString(HttpVersion& version, const std::string& str);
|
|
|
|
const char* ToString(HttpHeader header);
|
|
bool FromString(HttpHeader& header, const std::string& str);
|
|
|
|
bool HttpHeaderIsEndToEnd(HttpHeader header);
|
|
bool HttpHeaderIsCollapsible(HttpHeader header);
|
|
|
|
struct HttpData;
|
|
bool HttpShouldKeepAlive(const HttpData& data);
|
|
|
|
typedef std::pair<std::string, std::string> HttpAttribute;
|
|
typedef std::vector<HttpAttribute> HttpAttributeList;
|
|
void HttpParseAttributes(const char* data,
|
|
size_t len,
|
|
HttpAttributeList& attributes);
|
|
bool HttpHasAttribute(const HttpAttributeList& attributes,
|
|
const std::string& name,
|
|
std::string* value);
|
|
bool HttpHasNthAttribute(HttpAttributeList& attributes,
|
|
size_t index,
|
|
std::string* name,
|
|
std::string* value);
|
|
|
|
// Convert RFC1123 date (DoW, DD Mon YYYY HH:MM:SS TZ) to unix timestamp
|
|
bool HttpDateToSeconds(const std::string& date, time_t* seconds);
|
|
|
|
inline uint16_t HttpDefaultPort(bool secure) {
|
|
return secure ? HTTP_SECURE_PORT : HTTP_DEFAULT_PORT;
|
|
}
|
|
|
|
// Returns the http server notation for a given address
|
|
std::string HttpAddress(const SocketAddress& address, bool secure);
|
|
|
|
// functional for insensitive std::string compare
|
|
struct iless {
|
|
bool operator()(const std::string& lhs, const std::string& rhs) const {
|
|
return (::_stricmp(lhs.c_str(), rhs.c_str()) < 0);
|
|
}
|
|
};
|
|
|
|
// put quotes around a string and escape any quotes inside it
|
|
std::string quote(const std::string& str);
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// HttpData
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
struct HttpData {
|
|
typedef std::multimap<std::string, std::string, iless> HeaderMap;
|
|
typedef HeaderMap::const_iterator const_iterator;
|
|
typedef HeaderMap::iterator iterator;
|
|
|
|
HttpVersion version;
|
|
std::unique_ptr<StreamInterface> document;
|
|
|
|
HttpData();
|
|
|
|
enum HeaderCombine { HC_YES, HC_NO, HC_AUTO, HC_REPLACE, HC_NEW };
|
|
void changeHeader(const std::string& name,
|
|
const std::string& value,
|
|
HeaderCombine combine);
|
|
inline void addHeader(const std::string& name,
|
|
const std::string& value,
|
|
bool append = true) {
|
|
changeHeader(name, value, append ? HC_AUTO : HC_NO);
|
|
}
|
|
inline void setHeader(const std::string& name,
|
|
const std::string& value,
|
|
bool overwrite = true) {
|
|
changeHeader(name, value, overwrite ? HC_REPLACE : HC_NEW);
|
|
}
|
|
// Returns count of erased headers
|
|
size_t clearHeader(const std::string& name);
|
|
// Returns iterator to next header
|
|
iterator clearHeader(iterator header);
|
|
|
|
// keep in mind, this may not do what you want in the face of multiple headers
|
|
bool hasHeader(const std::string& name, std::string* value) const;
|
|
|
|
inline const_iterator begin() const { return headers_.begin(); }
|
|
inline const_iterator end() const { return headers_.end(); }
|
|
inline iterator begin() { return headers_.begin(); }
|
|
inline iterator end() { return headers_.end(); }
|
|
inline const_iterator begin(const std::string& name) const {
|
|
return headers_.lower_bound(name);
|
|
}
|
|
inline const_iterator end(const std::string& name) const {
|
|
return headers_.upper_bound(name);
|
|
}
|
|
inline iterator begin(const std::string& name) {
|
|
return headers_.lower_bound(name);
|
|
}
|
|
inline iterator end(const std::string& name) {
|
|
return headers_.upper_bound(name);
|
|
}
|
|
|
|
// Convenience methods using HttpHeader
|
|
inline void changeHeader(HttpHeader header,
|
|
const std::string& value,
|
|
HeaderCombine combine) {
|
|
changeHeader(ToString(header), value, combine);
|
|
}
|
|
inline void addHeader(HttpHeader header,
|
|
const std::string& value,
|
|
bool append = true) {
|
|
addHeader(ToString(header), value, append);
|
|
}
|
|
inline void setHeader(HttpHeader header,
|
|
const std::string& value,
|
|
bool overwrite = true) {
|
|
setHeader(ToString(header), value, overwrite);
|
|
}
|
|
inline void clearHeader(HttpHeader header) { clearHeader(ToString(header)); }
|
|
inline bool hasHeader(HttpHeader header, std::string* value) const {
|
|
return hasHeader(ToString(header), value);
|
|
}
|
|
inline const_iterator begin(HttpHeader header) const {
|
|
return headers_.lower_bound(ToString(header));
|
|
}
|
|
inline const_iterator end(HttpHeader header) const {
|
|
return headers_.upper_bound(ToString(header));
|
|
}
|
|
inline iterator begin(HttpHeader header) {
|
|
return headers_.lower_bound(ToString(header));
|
|
}
|
|
inline iterator end(HttpHeader header) {
|
|
return headers_.upper_bound(ToString(header));
|
|
}
|
|
|
|
virtual size_t formatLeader(char* buffer, size_t size) const = 0;
|
|
virtual HttpError parseLeader(const char* line, size_t len) = 0;
|
|
|
|
protected:
|
|
virtual ~HttpData();
|
|
void clear(bool release_document);
|
|
|
|
private:
|
|
HeaderMap headers_;
|
|
};
|
|
|
|
struct HttpRequestData : public HttpData {
|
|
std::string path;
|
|
|
|
HttpRequestData() {}
|
|
|
|
void clear(bool release_document);
|
|
|
|
size_t formatLeader(char* buffer, size_t size) const override;
|
|
HttpError parseLeader(const char* line, size_t len) override;
|
|
};
|
|
|
|
struct HttpResponseData : public HttpData {
|
|
uint32_t scode;
|
|
std::string message;
|
|
|
|
HttpResponseData() : scode(HC_INTERNAL_SERVER_ERROR) {}
|
|
void clear(bool release_document);
|
|
|
|
// Convenience methods
|
|
void set_success(uint32_t scode = HC_OK);
|
|
void set_error(uint32_t scode);
|
|
|
|
size_t formatLeader(char* buffer, size_t size) const override;
|
|
HttpError parseLeader(const char* line, size_t len) override;
|
|
};
|
|
|
|
struct HttpTransaction {
|
|
HttpRequestData request;
|
|
HttpResponseData response;
|
|
};
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Http Authentication
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
struct HttpAuthContext {
|
|
std::string auth_method;
|
|
HttpAuthContext(const std::string& auth) : auth_method(auth) {}
|
|
virtual ~HttpAuthContext() {}
|
|
};
|
|
|
|
enum HttpAuthResult { HAR_RESPONSE, HAR_IGNORE, HAR_CREDENTIALS, HAR_ERROR };
|
|
|
|
// 'context' is used by this function to record information between calls.
|
|
// Start by passing a null pointer, then pass the same pointer each additional
|
|
// call. When the authentication attempt is finished, delete the context.
|
|
// TODO(bugs.webrtc.org/8905): Change "response" to "ZeroOnFreeBuffer".
|
|
HttpAuthResult HttpAuthenticate(const char* challenge,
|
|
size_t len,
|
|
const SocketAddress& server,
|
|
const std::string& method,
|
|
const std::string& uri,
|
|
const std::string& username,
|
|
const CryptString& password,
|
|
HttpAuthContext*& context,
|
|
std::string& response,
|
|
std::string& auth_method);
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
} // namespace rtc
|
|
|
|
#endif // RTC_BASE_HTTPCOMMON_H_
|