CPPMyth
Library to interoperate with MythTV server
wsrequest.cpp
1 /*
2  * Copyright (C) 2014-2015 Jean-Luc Barriere
3  *
4  * This library is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU Lesser General Public License as published
6  * by the Free Software Foundation; either version 3, or (at your option)
7  * any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public License
15  * along with this library; see the file COPYING. If not, write to
16  * the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
17  * MA 02110-1301 USA
18  * http://www.gnu.org/copyleft/gpl.html
19  *
20  */
21 
22 #include "wsrequest.h"
23 #include "urlencoder.h"
24 #include "debug.h"
25 
26 #include <cstdio>
27 #include <cstring> // for strlen
28 
29 using namespace NSROOT;
30 
31 WSRequest::WSRequest(const std::string& server, unsigned port)
32 : m_server(server)
33 , m_port(port)
34 , m_secure_uri(false)
35 , m_service_url()
36 , m_service_method(HRM_GET)
37 , m_charset(REQUEST_STD_CHARSET)
38 , m_accept(CT_NONE)
39 , m_contentType(CT_FORM)
40 , m_contentData()
41 {
42  if (port == 443)
43  m_secure_uri = true;
44  // by default allow content encoding if possible
45  RequestAcceptEncoding(true);
46 }
47 
48 WSRequest::WSRequest(const std::string& server, unsigned port, bool secureURI)
49 : m_server(server)
50 , m_port(port)
51 , m_secure_uri(secureURI)
52 , m_service_url()
53 , m_service_method(HRM_GET)
54 , m_charset(REQUEST_STD_CHARSET)
55 , m_accept(CT_NONE)
56 , m_contentType(CT_FORM)
57 , m_contentData()
58 {
59  // by default allow content encoding if possible
60  RequestAcceptEncoding(true);
61 }
62 
63 WSRequest::WSRequest(const URIParser& uri, HRM_t method)
64 : m_port(0)
65 , m_secure_uri(false)
66 , m_service_method(method)
67 , m_charset(REQUEST_STD_CHARSET)
68 , m_accept(CT_NONE)
69 , m_contentType(CT_FORM)
70 , m_contentData()
71 {
72  if (uri.Host())
73  m_server.assign(uri.Host());
74  if (uri.Scheme() && strncmp(uri.Scheme(), "https", 5) == 0)
75  {
76  m_secure_uri = true;
77  m_port = uri.Port() ? uri.Port() : 443;
78  }
79  else
80  m_port = uri.Port() ? uri.Port() : 80;
81 
82  m_service_url = "/";
83  if (uri.Path())
84  m_service_url.append(uri.Path());
85 
86  // by default allow content encoding if possible
87  RequestAcceptEncoding(true);
88 }
89 
90 WSRequest::~WSRequest()
91 {
92 }
93 
94 void WSRequest::RequestService(const std::string& url, HRM_t method)
95 {
96  m_service_url = url;
97  m_service_method = method;
98 }
99 
100 void WSRequest::RequestAccept(CT_t contentType)
101 {
102  m_accept = contentType;
103 }
104 
105 void WSRequest::RequestAcceptEncoding(bool yesno)
106 {
107 #if HAVE_ZLIB
108  if (yesno)
109  SetHeader("Accept-Encoding", "gzip, deflate");
110  else
111  SetHeader("Accept-Encoding", "");
112 #else
113  (void)yesno;
114  SetHeader("Accept-Encoding", "");
115 #endif
116 }
117 
118 void WSRequest::SetUserAgent(const std::string& value)
119 {
120  m_userAgent = value;
121 }
122 
123 void WSRequest::SetContentParam(const std::string& param, const std::string& value)
124 {
125  if (m_contentType != CT_FORM)
126  return;
127  if (!m_contentData.empty())
128  m_contentData.append("&");
129  m_contentData.append(param).append("=").append(urlencode(value));
130 }
131 
132 void WSRequest::SetContentCustom(CT_t contentType, const char *content)
133 {
134  m_contentType = contentType;
135  m_contentData = content;
136 }
137 
138 void WSRequest::SetHeader(const std::string& field, const std::string& value)
139 {
140  m_headers[field] = value;
141 }
142 
143 void WSRequest::ClearContent()
144 {
145  m_contentData.clear();
146  m_contentType = CT_FORM;
147 }
148 
149 void WSRequest::MakeMessage(std::string& msg) const
150 {
151  switch (m_service_method)
152  {
153  case HRM_GET:
154  MakeMessageGET(msg);
155  break;
156  case HRM_POST:
157  MakeMessagePOST(msg);
158  break;
159  case HRM_HEAD:
160  MakeMessageHEAD(msg);
161  break;
162  case HRM_SUBSCRIBE:
163  MakeMessageHEAD(msg, "SUBSCRIBE");
164  break;
165  case HRM_UNSUBSCRIBE:
166  MakeMessageHEAD(msg, "UNSUBSCRIBE");
167  break;
168  case HRM_NOTIFY:
169  MakeMessagePOST(msg, "NOTIFY");
170  break;
171  default:
172  break;
173  }
174 }
175 
176 void WSRequest::MakeMessageGET(std::string& msg, const char* method) const
177 {
178  char buf[32];
179 
180  msg.clear();
181  msg.reserve(256);
182  msg.append(method).append(" ").append(m_service_url);
183  if (!m_contentData.empty())
184  msg.append("?").append(m_contentData);
185  msg.append(" " REQUEST_PROTOCOL "\r\n");
186  sprintf(buf, "%u", m_port);
187  msg.append("Host: ").append(m_server).append(":").append(buf).append("\r\n");
188  if (m_userAgent.empty())
189  msg.append("User-Agent: " REQUEST_USER_AGENT "\r\n");
190  else
191  msg.append("User-Agent: ").append(m_userAgent).append("\r\n");
192  msg.append("Connection: " REQUEST_CONNECTION "\r\n");
193  if (m_accept != CT_NONE)
194  msg.append("Accept: ").append(MimeFromContentType(m_accept)).append("\r\n");
195  msg.append("Accept-Charset: ").append(m_charset).append("\r\n");
196  for (std::map<std::string, std::string>::const_iterator it = m_headers.begin(); it != m_headers.end(); ++it)
197  msg.append(it->first).append(": ").append(it->second).append("\r\n");
198  msg.append("\r\n");
199 }
200 
201 void WSRequest::MakeMessagePOST(std::string& msg, const char* method) const
202 {
203  char buf[32];
204  size_t content_len = m_contentData.size();
205 
206  msg.clear();
207  msg.reserve(256);
208  msg.append(method).append(" ").append(m_service_url).append(" " REQUEST_PROTOCOL "\r\n");
209  sprintf(buf, "%u", m_port);
210  msg.append("Host: ").append(m_server).append(":").append(buf).append("\r\n");
211  if (m_userAgent.empty())
212  msg.append("User-Agent: " REQUEST_USER_AGENT "\r\n");
213  else
214  msg.append("User-Agent: ").append(m_userAgent).append("\r\n");
215  msg.append("Connection: " REQUEST_CONNECTION "\r\n");
216  if (m_accept != CT_NONE)
217  msg.append("Accept: ").append(MimeFromContentType(m_accept)).append("\r\n");
218  msg.append("Accept-Charset: ").append(m_charset).append("\r\n");
219  if (content_len)
220  {
221  sprintf(buf, "%lu", (unsigned long)content_len);
222  msg.append("Content-Type: ").append(MimeFromContentType(m_contentType));
223  msg.append("; charset=" REQUEST_STD_CHARSET "\r\n");
224  msg.append("Content-Length: ").append(buf).append("\r\n");
225  }
226  for (std::map<std::string, std::string>::const_iterator it = m_headers.begin(); it != m_headers.end(); ++it)
227  msg.append(it->first).append(": ").append(it->second).append("\r\n");
228  msg.append("\r\n");
229  if (content_len)
230  msg.append(m_contentData);
231 }
232 
233 void WSRequest::MakeMessageHEAD(std::string& msg, const char* method) const
234 {
235  char buf[32];
236 
237  msg.clear();
238  msg.reserve(256);
239  msg.append(method).append(" ").append(m_service_url);
240  if (!m_contentData.empty())
241  msg.append("?").append(m_contentData);
242  msg.append(" " REQUEST_PROTOCOL "\r\n");
243  sprintf(buf, "%u", m_port);
244  msg.append("Host: ").append(m_server).append(":").append(buf).append("\r\n");
245  if (m_userAgent.empty())
246  msg.append("User-Agent: " REQUEST_USER_AGENT "\r\n");
247  else
248  msg.append("User-Agent: ").append(m_userAgent).append("\r\n");
249  msg.append("Connection: " REQUEST_CONNECTION "\r\n");
250  if (m_accept != CT_NONE)
251  msg.append("Accept: ").append(MimeFromContentType(m_accept)).append("\r\n");
252  msg.append("Accept-Charset: ").append(m_charset).append("\r\n");
253  for (std::map<std::string, std::string>::const_iterator it = m_headers.begin(); it != m_headers.end(); ++it)
254  msg.append(it->first).append(": ").append(it->second).append("\r\n");
255  msg.append("\r\n");
256 }