1 /*****************************************************************
3 | Platinum - HTTP Protocol Helper
5 | Copyright (c) 2004-2010, Plutinosoft, LLC.
7 | http://www.plutinosoft.com
9 | This program is free software; you can redistribute it and/or
10 | modify it under the terms of the GNU General Public License
11 | as published by the Free Software Foundation; either version 2
12 | of the License, or (at your option) any later version.
14 | OEMs, ISVs, VARs and other distributors that combine and
15 | distribute commercially licensed software with Platinum software
16 | and do not wish to distribute the source code for the commercially
17 | licensed software under version 2, or (at your option) any later
18 | version, of the GNU General Public License (the "GPL") must enter
19 | into a commercial license agreement with Plutinosoft, LLC.
20 | licensing@plutinosoft.com
22 | This program is distributed in the hope that it will be useful,
23 | but WITHOUT ANY WARRANTY; without even the implied warranty of
24 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 | GNU General Public License for more details.
27 | You should have received a copy of the GNU General Public License
28 | along with this program; see the file LICENSE.txt. If not, write to
29 | the Free Software Foundation, Inc.,
30 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
31 | http://www.gnu.org/licenses/gpl-2.0.html
33 ****************************************************************/
35 /*----------------------------------------------------------------------
37 +---------------------------------------------------------------------*/
39 #include "PltDatagramStream.h"
40 #include "PltVersion.h"
41 #include "PltUtilities.h"
43 NPT_SET_LOCAL_LOGGER("platinum.core.http")
45 /*----------------------------------------------------------------------
47 +---------------------------------------------------------------------*/
48 extern NPT_String HttpServerHeader
;
50 /*----------------------------------------------------------------------
51 | NPT_HttpHeaderFinder
52 +---------------------------------------------------------------------*/
53 class NPT_HttpHeaderFinder
57 NPT_HttpHeaderFinder(const char* name
) : m_Name(name
) {}
58 bool operator()(const NPT_HttpHeader
* const & header
) const {
59 if (header
->GetName().Compare(m_Name
, true)) {
71 /*----------------------------------------------------------------------
72 | NPT_HttpHeaderLogger
73 +---------------------------------------------------------------------*/
74 class NPT_HttpHeaderLogger
78 NPT_HttpHeaderLogger(NPT_LoggerReference
& logger
, int level
) :
79 m_Logger(logger
), m_Level(level
) {}
80 NPT_Result
operator()(NPT_HttpHeader
*& header
) const {
81 NPT_COMPILER_UNUSED(header
);
83 NPT_LOG_L2(m_Logger
, m_Level
, "%s: %s",
84 (const char*)header
->GetName(),
85 (const char*)header
->GetValue());
89 NPT_LoggerReference
& m_Logger
;
94 /*----------------------------------------------------------------------
95 | PLT_HttpHelper::GetContentType
96 +---------------------------------------------------------------------*/
98 PLT_HttpHelper::GetContentType(const NPT_HttpMessage
& message
,
103 const NPT_String
* val
=
104 message
.GetHeaders().GetHeaderValue(NPT_HTTP_HEADER_CONTENT_TYPE
);
105 NPT_CHECK_POINTER(val
);
111 /*----------------------------------------------------------------------
112 | PLT_HttpHelper::GetContentLength
113 +---------------------------------------------------------------------*/
115 PLT_HttpHelper::GetContentLength(const NPT_HttpMessage
& message
,
120 const NPT_String
* val
=
121 message
.GetHeaders().GetHeaderValue(NPT_HTTP_HEADER_CONTENT_LENGTH
);
122 NPT_CHECK_POINTER(val
);
124 return val
->ToInteger64(len
);
127 /*----------------------------------------------------------------------
128 | PLT_HttpHelper::SetBody
129 +---------------------------------------------------------------------*/
131 PLT_HttpHelper::SetBody(NPT_HttpMessage
& message
,
133 NPT_HttpEntity
** entity
/* = NULL */)
135 return SetBody(message
, (const char*)text
, text
.GetLength(), entity
);
138 /*----------------------------------------------------------------------
139 | PLT_HttpHelper::SetBody
140 +---------------------------------------------------------------------*/
142 PLT_HttpHelper::SetBody(NPT_HttpMessage
& message
,
144 NPT_HttpEntity
** entity
/* = NULL */)
146 return SetBody(message
, (const char*)text
, NPT_StringLength(text
), entity
);
149 /*----------------------------------------------------------------------
150 | NPT_HttpMessage::SetBody
151 +---------------------------------------------------------------------*/
153 PLT_HttpHelper::SetBody(NPT_HttpMessage
& message
,
156 NPT_HttpEntity
** entity
/* = NULL */)
158 if (len
== 0) return NPT_SUCCESS
;
160 // dump the body in a memory stream
161 NPT_MemoryStreamReference
stream(new NPT_MemoryStream
);
162 stream
->Write(body
, (NPT_Size
)len
);
164 // set content length
165 return SetBody(message
, (NPT_InputStreamReference
)stream
, entity
);
168 /*----------------------------------------------------------------------
169 | NPT_HttpMessage::SetBody
170 +---------------------------------------------------------------------*/
172 PLT_HttpHelper::SetBody(NPT_HttpMessage
& message
,
173 NPT_InputStreamReference stream
,
174 NPT_HttpEntity
** entity
/* = NULL */)
177 NPT_HttpEntity
* _entity
= message
.GetEntity();
178 if (_entity
== NULL
) {
179 // no entity yet, create one
180 message
.SetEntity(_entity
= new NPT_HttpEntity());
183 if (entity
) *entity
=_entity
;
185 // set the entity body
186 return _entity
->SetInputStream(stream
, true);
189 /*----------------------------------------------------------------------
190 | PLT_HttpHelper::GetBody
191 +---------------------------------------------------------------------*/
193 PLT_HttpHelper::GetBody(const NPT_HttpMessage
& message
, NPT_String
& body
)
196 NPT_InputStreamReference stream
;
199 NPT_HttpEntity
* entity
= message
.GetEntity();
201 NPT_FAILED(entity
->GetInputStream(stream
)) ||
207 NPT_StringOutputStream
* output_stream
= new NPT_StringOutputStream(&body
);
208 res
= NPT_StreamToStreamCopy(*stream
,
211 entity
->GetContentLength());
212 delete output_stream
;
216 /*----------------------------------------------------------------------
217 | PLT_HttpHelper::ParseBody
218 +---------------------------------------------------------------------*/
220 PLT_HttpHelper::ParseBody(const NPT_HttpMessage
& message
,
221 NPT_XmlElementNode
*& tree
)
228 NPT_CHECK_WARNING(GetBody(message
, body
));
230 return PLT_XmlHelper::Parse(body
, tree
);
233 /*----------------------------------------------------------------------
234 | PLT_HttpHelper::IsConnectionKeepAlive
235 +---------------------------------------------------------------------*/
237 PLT_HttpHelper::IsConnectionKeepAlive(NPT_HttpMessage
& message
)
239 const NPT_String
* connection
=
240 message
.GetHeaders().GetHeaderValue(NPT_HTTP_HEADER_CONNECTION
);
242 // the DLNA says that all HTTP 1.0 requests should be closed immediately by the server
243 NPT_String protocol
= message
.GetProtocol();
244 if (protocol
.Compare(NPT_HTTP_PROTOCOL_1_0
, true) == 0) return false;
246 // all HTTP 1.1 requests without a Connection header
247 // or with a keep-alive Connection header should be kept alive if possible
248 return (!connection
|| connection
->Compare("keep-alive", true) == 0);
251 /*----------------------------------------------------------------------
252 | PLT_HttpHelper::IsBodyStreamSeekable
253 +---------------------------------------------------------------------*/
255 PLT_HttpHelper::IsBodyStreamSeekable(NPT_HttpMessage
& message
)
257 NPT_HttpEntity
* entity
= message
.GetEntity();
258 NPT_InputStreamReference stream
;
261 NPT_FAILED(entity
->GetInputStream(stream
)) ||
266 // try to get current position and seek there
267 NPT_Position position
;
268 if (NPT_FAILED(stream
->Tell(position
)) ||
269 NPT_FAILED(stream
->Seek(position
))) {
276 /*----------------------------------------------------------------------
277 | PLT_HttpHelper::GetHost
278 +---------------------------------------------------------------------*/
280 PLT_HttpHelper::GetHost(const NPT_HttpRequest
& request
, NPT_String
& value
)
284 const NPT_String
* val
=
285 request
.GetHeaders().GetHeaderValue(NPT_HTTP_HEADER_HOST
);
286 NPT_CHECK_POINTER(val
);
292 /*----------------------------------------------------------------------
293 | PLT_HttpHelper::SetHost
294 +---------------------------------------------------------------------*/
296 PLT_HttpHelper::SetHost(NPT_HttpRequest
& request
, const char* host
)
298 request
.GetHeaders().SetHeader(NPT_HTTP_HEADER_HOST
, host
);
301 /*----------------------------------------------------------------------
302 | PLT_HttpHelper::GetDeviceSignature
303 +---------------------------------------------------------------------*/
305 PLT_HttpHelper::GetDeviceSignature(const NPT_HttpRequest
& request
)
307 const NPT_String
* agent
= request
.GetHeaders().GetHeaderValue(NPT_HTTP_HEADER_USER_AGENT
);
308 const NPT_String
* hdr
= request
.GetHeaders().GetHeaderValue("X-AV-Client-Info");
309 const NPT_String
* server
= request
.GetHeaders().GetHeaderValue(NPT_HTTP_HEADER_SERVER
);
310 const NPT_String
* dlna_friendly_name
= request
.GetHeaders().GetHeaderValue("FriendlyName.DLNA.ORG");
311 NPT_LOG_FINEST_2("agent: %s, server: %s", agent
?agent
->GetChars():"none", server
?server
->GetChars():"none");
313 if ((agent
&& (agent
->Find("XBox", 0, true) >= 0 || agent
->Find("Xenon", 0, true) >= 0)) ||
314 (server
&& server
->Find("Xbox", 0, true) >= 0)) {
315 return PLT_DEVICE_XBOX_360
;
316 } else if(dlna_friendly_name
&& (dlna_friendly_name
->Find("XBOX-ONE", 0, true) >= 0)) {
317 return PLT_DEVICE_XBOX_ONE
;
318 } else if (agent
&& (agent
->Find("Windows Media Player", 0, true) >= 0 || agent
->Find("Windows-Media-Player", 0, true) >= 0 || agent
->Find("Mozilla/4.0", 0, true) >= 0 || agent
->Find("WMFSDK", 0, true) >= 0)) {
319 return PLT_DEVICE_WMP
;
320 } else if (agent
&& (agent
->Find("Sonos", 0, true) >= 0)) {
321 return PLT_DEVICE_SONOS
;
322 } else if ((agent
&& agent
->Find("PLAYSTATION 3", 0, true) >= 0) ||
323 (hdr
&& hdr
->Find("PLAYSTATION 3", 0, true) >= 0)) {
324 return PLT_DEVICE_PS3
;
325 } else if (agent
&& agent
->Find("Windows", 0, true) >= 0) {
326 return PLT_DEVICE_WINDOWS
;
327 } else if (agent
&& (agent
->Find("Mac", 0, true) >= 0 || agent
->Find("OS X", 0, true) >= 0 || agent
->Find("OSX", 0, true) >= 0)) {
328 return PLT_DEVICE_MAC
;
329 } else if (agent
&& (agent
->Find("VLC", 0, true) >= 0 || agent
->Find("VideoLan", 0, true) >= 0)) {
330 return PLT_DEVICE_VLC
;
332 NPT_LOG_FINER_2("Unknown device signature (ua=%s, server=%s)", agent
?agent
->GetChars():"none", server
?server
->GetChars():"none");
335 return PLT_DEVICE_UNKNOWN
;
338 /*----------------------------------------------------------------------
339 | PLT_HttpHelper::SetBasicAuthorization
340 +---------------------------------------------------------------------*/
342 PLT_HttpHelper::SetBasicAuthorization(NPT_HttpRequest
& request
,
343 const char* username
,
344 const char* password
)
347 NPT_String cred
= NPT_String(username
) + ":" + password
;
349 NPT_Base64::Encode((const NPT_Byte
*)cred
.GetChars(), cred
.GetLength(), encoded
);
350 request
.GetHeaders().SetHeader(NPT_HTTP_HEADER_AUTHORIZATION
, NPT_String("Basic " + encoded
));