blob: 89b9557041f437b61a56840dc1bd7bdb916e0310 [file] [log] [blame]
// Copyright 2015 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <memory>
#include <string>
#include <tuple>
#include <utility>
#include <vector>
#include <base/files/file.h>
#include <base/files/file_path.h>
#include <base/macros.h>
#include <base/memory/weak_ptr.h>
#include <brillo/streams/stream.h>
struct MHD_Connection;
struct MHD_PostProcessor;
namespace webservd {
class ProtocolHandler;
class TempFileManager;
using PairOfStrings = std::pair<std::string, std::string>;
// This class represents the file information about a file uploaded via
// POST request using multipart/form-data request.
class FileInfo final {
FileInfo(const std::string& in_field_name,
const std::string& in_file_name,
const std::string& in_content_type,
const std::string& in_transfer_encoding);
FileInfo(const FileInfo&) = delete;
FileInfo& operator=(const FileInfo&) = delete;
// The name of the form field for the file upload.
std::string field_name;
// The name of the file name specified in the form field.
std::string file_name;
// The content type of the file data.
std::string content_type;
// Data transfer encoding specified. Could be empty if no transfer encoding
// was specified.
std::string transfer_encoding;
// The file content data.
brillo::StreamPtr data_stream;
// The temporary file containing the file part data.
base::FilePath temp_file_name;
// A class that represents the HTTP request data.
class Request final {
Request(const std::string& request_handler_id,
const std::string& url,
const std::string& method,
const std::string& version,
MHD_Connection* connection,
ProtocolHandler* protocol_handler);
Request(const Request&) = delete;
Request& operator=(const Request&) = delete;
// Obtains the file descriptor containing data of uploaded file identified
// by |file_id|.
base::File GetFileData(int file_id);
// Finishes the request and provides the reply data.
base::File Complete(
int32_t status_code,
const std::vector<std::tuple<std::string, std::string>>& headers,
int64_t in_data_size);
// Helper function to provide the string data and mime type.
bool Complete(
int32_t status_code,
const std::vector<std::tuple<std::string, std::string>>& headers,
const std::string& mime_type,
const std::string& data);
// Returns the unique ID of this request (GUID).
const std::string& GetID() const { return id_; }
// Returns the unique ID of the request handler this request is processed by
// (GUID).
const std::string& GetRequestHandlerID() const { return request_handler_id_; }
// Returns the unique ID of the protocol handler this request is received
// from (GUID or "http"/"https" for the two default handlers).
const std::string& GetProtocolHandlerID() const;
// Returns the object path of the HTTP request (e.g. "/privet/info").
const std::string& GetURL() const { return url_; }
// Returns the request method (e.g. "GET", "POST", ...).
const std::string& GetMethod() const { return method_; }
// Returns the output end of the body data stream pipe. The file descriptor
// is owned by the caller and must be closed when no longer needed.
// The pipe will contain the request body data, or no data if the request
// had no body or a POST request has been parsed into form data.
// In case there is no data, the file descriptor will represent a closed pipe,
// so reading from it will just indicate end-of-file (no data to read).
int GetBodyDataFileDescriptor() const;
// Returns the POST form field data.
const std::vector<PairOfStrings>& GetDataPost() const { return post_data_; }
// Returns query parameters specified on the URL (as in "?param=value").
const std::vector<PairOfStrings>& GetDataGet() const { return get_data_; }
// Returns the information about any files uploaded as part of POST request.
const std::vector<std::unique_ptr<FileInfo>>& GetFileInfo() const {
return file_info_;
// Returns the HTTP request headers.
const std::vector<PairOfStrings>& GetHeaders() const { return headers_; }
friend class RequestHelper;
friend class ServerHelper;
// Helper methods for processing request data coming from the raw HTTP
// connection.
// Helper callback methods used by ProtocolHandler's ConnectionHandler to
// transfer request headers and data to the Request object.
bool BeginRequestData();
bool AddRequestData(const void* data, size_t* size);
void EndRequestData();
// Callback for libmicrohttpd's PostProcessor.
bool ProcessPostData(const char* key,
const char* filename,
const char* content_type,
const char* transfer_encoding,
const char* data,
uint64_t off,
size_t size);
// These methods parse the request headers and data so they can be accessed
// by request handlers later.
// AddRawRequestData takes the amount of data to write in |*size|. On output,
// |*size| contains the number of bytes REMAINING to be written, or 0 if all
// data have been written successfully.
bool AddRawRequestData(const void* data, size_t* size);
bool AddPostFieldData(const char* key,
const char* filename,
const char* content_type,
const char* transfer_encoding,
const char* data,
size_t size);
bool AppendPostFieldData(const char* key, const char* data, size_t size);
// Callback to be called when data can be written to the output pipe again.
void OnPipeAvailable(brillo::Stream::AccessMode mode);
// Forwards the request to the request handler.
void ForwardRequestToHandler();
// Response data callback for MHD_create_response_from_callback().
static ssize_t ResponseDataCallback(void* cls,
uint64_t pos,
char* buf,
size_t max);
TempFileManager* GetTempFileManager();
std::string id_;
std::string request_handler_id_;
std::string url_;
std::string method_;
std::string version_;
MHD_Connection* connection_{nullptr};
MHD_PostProcessor* post_processor_{nullptr};
// Data pipe for request body data (output/read end of the pipe).
base::File request_data_pipe_out_;
// Data stream for the input/write end of the request data pipe.
brillo::StreamPtr request_data_stream_;
bool last_posted_data_was_file_{false};
bool request_forwarded_{false};
bool request_data_finished_{false};
bool response_data_started_{false};
bool response_data_finished_{false};
bool waiting_for_data_{false};
std::vector<PairOfStrings> post_data_;
std::vector<PairOfStrings> get_data_;
std::vector<std::unique_ptr<FileInfo>> file_info_;
std::vector<PairOfStrings> headers_;
int response_status_code_{0};
// Data size of response, -1 if unknown.
int64_t response_data_size_{-1};
// Data stream for the output/read end of the response data pipe.
brillo::StreamPtr response_data_stream_;
std::vector<PairOfStrings> response_headers_;
ProtocolHandler* protocol_handler_;
base::WeakPtrFactory<Request> weak_ptr_factory_{this};
} // namespace webservd