1// Aseprite Network Library
2// Copyright (c) 2001-2016 David Capello
3//
4// This file is released under the terms of the MIT license.
5// Read LICENSE.txt for more information.
6
7#ifdef HAVE_CONFIG_H
8#include "config.h"
9#endif
10
11#include "net/http_request.h"
12
13#include "base/debug.h"
14#include "net/http_headers.h"
15#include "net/http_response.h"
16
17#include <curl/curl.h>
18
19namespace net {
20
21class HttpRequestImpl {
22public:
23 HttpRequestImpl(const std::string& url)
24 : m_curl(curl_easy_init())
25 , m_headerlist(nullptr)
26 , m_response(nullptr) {
27 curl_easy_setopt(m_curl, CURLOPT_WRITEDATA, this);
28 curl_easy_setopt(m_curl, CURLOPT_WRITEFUNCTION, &HttpRequestImpl::writeBodyCallback);
29 curl_easy_setopt(m_curl, CURLOPT_URL, url.c_str());
30 curl_easy_setopt(m_curl, CURLOPT_NOSIGNAL, 1);
31 }
32
33 ~HttpRequestImpl() {
34 if (m_headerlist)
35 curl_slist_free_all(m_headerlist);
36
37 curl_easy_cleanup(m_curl);
38 }
39
40 void setHeaders(const HttpHeaders& headers) {
41 if (m_headerlist) {
42 curl_slist_free_all(m_headerlist);
43 m_headerlist = NULL;
44 }
45
46 std::string tmp;
47 for (HttpHeaders::const_iterator it=headers.begin(), end=headers.end(); it!=end; ++it) {
48 tmp = it->first;
49 tmp += ": ";
50 tmp += it->second;
51
52 m_headerlist = curl_slist_append(m_headerlist, tmp.c_str());
53 }
54
55 curl_easy_setopt(m_curl, CURLOPT_HTTPHEADER, m_headerlist);
56 }
57
58 bool send(HttpResponse& response) {
59 m_response = &response;
60 int res = curl_easy_perform(m_curl);
61 if (res != CURLE_OK)
62 return false;
63
64 long code;
65 curl_easy_getinfo(m_curl, CURLINFO_RESPONSE_CODE, &code);
66 m_response->setStatus(code);
67 return true;
68 }
69
70 void abort() {
71 curl_easy_setopt(m_curl, CURLOPT_TIMEOUT_MS, 1);
72 curl_easy_setopt(m_curl, CURLOPT_CONNECTTIMEOUT_MS, 1);
73 }
74
75private:
76 std::size_t writeBody(char* ptr, std::size_t bytes) {
77 ASSERT(m_response != NULL);
78 m_response->write(ptr, bytes);
79 return bytes;
80 }
81
82 static std::size_t writeBodyCallback(char* ptr, std::size_t size, std::size_t nmemb, void* userdata) {
83 HttpRequestImpl* req = reinterpret_cast<HttpRequestImpl*>(userdata);
84 return req->writeBody(ptr, size*nmemb);
85 }
86
87 CURL* m_curl;
88 curl_slist* m_headerlist;
89 HttpResponse* m_response;
90};
91
92HttpRequest::HttpRequest(const std::string& url)
93 : m_impl(new HttpRequestImpl(url))
94{
95}
96
97HttpRequest::~HttpRequest()
98{
99 delete m_impl;
100}
101
102void HttpRequest::setHeaders(const HttpHeaders& headers)
103{
104 m_impl->setHeaders(headers);
105}
106
107bool HttpRequest::send(HttpResponse& response)
108{
109 return m_impl->send(response);
110}
111
112void HttpRequest::abort()
113{
114 m_impl->abort();
115}
116
117} // namespace net
118