1 /***************************************************************************
2 ulxr_http_protocol.cpp - http prootocol
3 -------------------
4 begin : Mon May 3 2004
5 copyright : (C) 2002-2007 by Ewald Arnold
6 email : ulxmlrpcpp@ewald-arnold.de
7
8 $Id: ulxr_http_protocol.cpp 1164 2010-01-06 10:03:51Z ewald-arnold $
9
10 ***************************************************************************/
11
12 /**************************************************************************
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License as
16 * published by the Free Software Foundation; either version 2 of the License,
17 * or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU Lesser General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 *
28 ***************************************************************************/
29
30 // #define ULXR_SHOW_TRACE
31 // #define ULXR_DEBUG_OUTPUT
32 // #define ULXR_SHOW_HTTP
33 // #define ULXR_SHOW_READ
34 // #define ULXR_SHOW_WRITE
35 // #define ULXR_SHOW_XML
36
37
38 #define ULXR_NEED_EXPORTS
39 #include <ulxmlrpcpp/ulxmlrpcpp.h> // always first
40
41 #include <cstdlib>
42 #include <cstdio>
43 #include <ctime>
44 #include <sys/stat.h>
45
46 #include <cstring>
47
48 #if defined(__BORLANDC__) || defined (_MSC_VER)
49 #include <utility>
50 #endif
51
52 #include <ulxmlrpcpp/ulxr_http_protocol.h>
53 #include <ulxmlrpcpp/ulxr_tcpip_connection.h>
54 #include <ulxmlrpcpp/ulxr_except.h>
55 #include <ulxmlrpcpp/ulxr_response.h>
56 #include <ulxmlrpcpp/ulxr_call.h>
57
58 #ifndef ULXR_OMIT_REENTRANT_PROTECTOR
59 #include <ulxmlrpcpp/ulxr_mutex.h>
60 #endif
61
62
63 namespace ulxr
64 {
65
66 struct HttpProtocol::PImpl
67 {
68 CppString proxy_user;
69 CppString proxy_pass;
70 CppString useragent;
71 CppString header_firstline;
72 CppString header_buffer;
73 CppString hostname;
74 unsigned hostport;
75
76 bool useconnect;
77 bool connected;
78
79 ConnectorWrapperBase *connector;
80
81 bool bChunkedEncoding;
82 int chunk_size;
83 bool chunk_terminated;
84 bool chunk_in_header;
85 Cpp8BitString chunk_data;
86 unsigned chunked_block;
87 unsigned chunk_body_skip;
88
89 bool bAcceptcookies;
90 std::map<CppString, CppString> cookies;
91 CppString serverCookie;
92 CppString clientCookie;
93 std::vector<CppString> userTempFields;
94 header_property headerprops;
95 };
96
97
HttpProtocol(const HttpProtocol & prot)98 ULXR_API_IMPL0 HttpProtocol::HttpProtocol(const HttpProtocol &prot)
99 : Protocol(prot)
100 , pimpl(new PImpl)
101 {
102 *pimpl = *prot.pimpl;
103 }
104
105
106 ULXR_API_IMPL0
HttpProtocol(Connection * conn,const CppString & hn,unsigned hp)107 HttpProtocol::HttpProtocol(Connection *conn, const CppString &hn, unsigned hp)
108 : Protocol (conn)
109 , pimpl(new PImpl)
110 {
111 pimpl->hostname = hn;
112 pimpl->hostport = hp;
113 ULXR_TRACE(ULXR_PCHAR("HttpProtocol(conn, name, port)"));
114 init();
115 }
116
117
118 ULXR_API_IMPL0
HttpProtocol(TcpIpConnection * conn)119 HttpProtocol::HttpProtocol(TcpIpConnection *conn)
120 : Protocol (conn)
121 , pimpl(new PImpl)
122 {
123 pimpl->hostname = conn->getPeerName();
124 pimpl->hostport = conn->getPort();
125 ULXR_TRACE(ULXR_PCHAR("HttpProtocol(conn)"));
126 init();
127 }
128
129
~HttpProtocol()130 ULXR_API_IMPL0 HttpProtocol::~HttpProtocol()
131 {
132 ULXR_TRACE(ULXR_PCHAR("~HttpProtocol"));
133 delete pimpl->connector;
134 delete pimpl;
135 pimpl = 0;
136 }
137
138
ULXR_API_IMPL(HttpProtocol *)139 ULXR_API_IMPL(HttpProtocol *) HttpProtocol::clone() const
140 {
141 ULXR_TRACE(ULXR_PCHAR("HttpProtocol::clone()"));
142 return new HttpProtocol(*this);
143 }
144
145
ULXR_API_IMPL(Protocol *)146 ULXR_API_IMPL(Protocol *) HttpProtocol::detach()
147 {
148 ULXR_TRACE(ULXR_PCHAR("HttpProtocol::detach()"));
149 HttpProtocol *cloneprot = this->clone();
150 cloneprot->setConnection(getConnection()->detach());
151 cloneprot->pimpl->connector = new ConnectorWrapper<HttpProtocol>(cloneprot, &HttpProtocol::doConnect);
152 return cloneprot; // return previous and running connection
153 }
154
155
ULXR_API_IMPL(void)156 ULXR_API_IMPL(void) HttpProtocol::init()
157 {
158 ULXR_TRACE(ULXR_PCHAR("init"));
159 pimpl->connector = new ConnectorWrapper<HttpProtocol>(this, &HttpProtocol::doConnect);
160 getConnection()->setConnector(pimpl->connector);
161 pimpl->useconnect = false;
162 pimpl->connected = false;
163 ULXR_TRACE(ULXR_PCHAR("init"));
164 pimpl->headerprops.clear();
165 pimpl->useragent = ULXR_GET_STRING(ULXR_PACKAGE) + ULXR_PCHAR("/") + ULXR_GET_STRING(ULXR_VERSION);
166 pimpl->userTempFields.clear();
167 pimpl->bAcceptcookies = false;
168 pimpl->bChunkedEncoding = false;
169 pimpl->chunk_data.clear();
170 pimpl->chunk_size = 0;
171 pimpl->chunk_body_skip = 0;
172 setChunkedTransfer(false);
173 }
174
175
ULXR_API_IMPL(void)176 ULXR_API_IMPL(void) HttpProtocol::clearHttpInfo()
177 {
178 ULXR_TRACE(ULXR_PCHAR("clearHttpInfo"));
179 pimpl->header_firstline = ULXR_PCHAR("");
180 pimpl->header_buffer = ULXR_PCHAR("");
181 pimpl->headerprops.clear();
182 pimpl->cookies.clear();
183 pimpl->bChunkedEncoding = false;
184 pimpl->chunk_data.clear();
185 pimpl->chunk_size = 0;
186 pimpl->chunk_body_skip = 0;
187 pimpl->chunk_terminated = false;
188 pimpl->chunk_in_header = true;
189 }
190
191
ULXR_API_IMPL(void)192 ULXR_API_IMPL(void) HttpProtocol::resetConnection()
193 {
194 ULXR_TRACE(ULXR_PCHAR("resetConnection"));
195 Protocol::resetConnection();
196 clearHttpInfo();
197 //loadCookie(peername);
198 }
199
200
ULXR_API_IMPL(void)201 ULXR_API_IMPL(void) HttpProtocol::close()
202 {
203 ULXR_TRACE(ULXR_PCHAR("close"));
204 Protocol::close();
205 pimpl->connected = false;
206 // storeCookie(peername);
207 }
208
209
ULXR_API_IMPL(void)210 ULXR_API_IMPL(void) HttpProtocol::shutdown(int mode)
211 {
212 ULXR_TRACE(ULXR_PCHAR("shutdown"));
213 if (getConnection() != 0)
214 getConnection()->shutdown(mode);
215 }
216
217
ULXR_API_IMPL(CppString)218 ULXR_API_IMPL(CppString) HttpProtocol::getHttpProperty(const CppString &in_name) const
219 {
220 ULXR_TRACE(ULXR_PCHAR("getHttpProperty ") << in_name);
221 CppString name = in_name;
222 makeLower(name);
223 header_property::const_iterator it;
224
225 if ((it = pimpl->headerprops.find(name)) == pimpl->headerprops.end() )
226 throw ConnectionException(NotConformingError,
227 ulxr_i18n(ULXR_PCHAR("Http property field not available: "))+name, 400);
228
229 return (*it).second;
230 }
231
232
ULXR_API_IMPL(bool)233 ULXR_API_IMPL(bool) HttpProtocol::hasHttpProperty(const CppString &in_name) const
234 {
235 CppString name = in_name;
236 makeLower(name);
237 bool b = pimpl->headerprops.find(name) != pimpl->headerprops.end();
238 ULXR_TRACE(ULXR_PCHAR("hasHttpProperty: ") << in_name << ULXR_PCHAR(" ") << b);
239 return b;
240 }
241
242
ULXR_API_IMPL(void)243 ULXR_API_IMPL(void) HttpProtocol::parseHeaderLine()
244 {
245 ULXR_TRACE(ULXR_PCHAR("parseHeaderLine"));
246
247 if (pimpl->header_firstline.length() == 0)
248 {
249 pimpl->header_firstline = pimpl->header_buffer;
250 ULXR_DOUT_HTTP(ULXR_PCHAR("firstline: <") << pimpl->header_firstline << ULXR_PCHAR(">"));
251 }
252 else
253 {
254 CppString nm, cont;
255 std::size_t pos = pimpl->header_buffer.find(':');
256 if (pos == CppString::npos)
257 {
258 nm = pimpl->header_buffer;
259 cont = ULXR_PCHAR("");
260 }
261 else
262 {
263 nm = pimpl->header_buffer.substr(0, pos);
264 cont = pimpl->header_buffer.substr(pos+1);
265 }
266
267 makeLower(nm);
268 cont = stripWS(cont);
269 nm = stripWS(nm);
270 pimpl->headerprops.insert(std::make_pair(nm, cont));
271
272 if (pimpl->bAcceptcookies && (nm == ULXR_PCHAR("set-cookie"))) // distinguish between cookie / set-cookie?
273 setCookie(cont);
274
275 else if (pimpl->bAcceptcookies && (nm == ULXR_PCHAR("cookie")))
276 setCookie(cont);
277
278 ULXR_DOUT_HTTP(ULXR_PCHAR("headerprop: <") << nm
279 << ULXR_PCHAR("> + <") << cont << ULXR_PCHAR("> "));
280 }
281 pimpl->header_buffer = ULXR_PCHAR("");
282 }
283
284
hasClosingProperty()285 bool HttpProtocol::hasClosingProperty()
286 {
287 bool do_close = false;
288 if (hasHttpProperty(ULXR_PCHAR("connection")))
289 {
290 CppString sConnect = getHttpProperty(ULXR_PCHAR("connection"));
291 makeLower(sConnect);
292 if (sConnect == CppString(ULXR_PCHAR("close")))
293 do_close = true;
294 }
295
296 if (hasHttpProperty(ULXR_PCHAR("proxy-connection")))
297 {
298 CppString sConnect = getHttpProperty(ULXR_PCHAR("proxy-connection"));
299 makeLower(sConnect);
300 if (sConnect == CppString(ULXR_PCHAR("close")))
301 do_close = true;
302 }
303 return do_close;
304 }
305
306
ULXR_API_IMPL(bool)307 ULXR_API_IMPL(bool) HttpProtocol::checkContinue()
308 {
309 ULXR_TRACE(ULXR_PCHAR("checkContinue"));
310 CppString head_version;
311 unsigned head_status = 500;
312 CppString head_phrase;
313 splitHeaderLine(head_version, head_status, head_phrase);
314 if (head_status == 100)
315 {
316 ULXR_TRACE(ULXR_PCHAR("Ignoring header 100-Continue"));
317 setConnectionState(ConnStart);
318 return true;
319 }
320 else
321 return false;
322 }
323
324
ULXR_API_IMPL(Protocol::State)325 ULXR_API_IMPL(Protocol::State)
326 HttpProtocol::connectionMachine(char * &buffer, long &len)
327 {
328 /*
329 Each invokation of this state machine tries to parse one single
330 http header line of the buffer. If the content of the buffer is too small
331 (no linefeed found) the content is cached in an internal string
332 and used the next time.
333 buffer points to the beginning of the next line at return if
334 a linefeed has been found. In the message body nothing is done.
335 */
336 ULXR_TRACE(ULXR_PCHAR("connectionMachine with ") << len << ULXR_PCHAR(" bytes"));
337 if (len == 0 || buffer == 0)
338 return getConnectionState();
339
340 char *chunk_cursor = buffer;
341 char *chunk_start = buffer;
342
343 while (len > 0)
344 {
345 const unsigned state = getConnectionState();
346 switch (state)
347 {
348 case ConnStart:
349 setConnectionState(ConnHeaderLine);
350 clearHttpInfo();
351 break;
352
353 case ConnPendingCR:
354 if (*buffer == '\n') // CR+LF
355 {
356 --len;
357 ++buffer;
358 }
359
360 if (pimpl->header_buffer.length() == 0)
361 setConnectionState(ConnSwitchToBody);
362 else
363 setConnectionState(ConnPendingHeaderLine);
364 break;
365
366 case ConnPendingHeaderLine:
367 if (pimpl->header_buffer.length() == 0)
368 setConnectionState(ConnSwitchToBody);
369
370 else if (*buffer != ' ') // continuation line of current header field?
371 {
372 parseHeaderLine();
373 setConnectionState(ConnHeaderLine);
374 }
375 else
376 setConnectionState(ConnHeaderLine);
377 break;
378
379 case ConnHeaderLine:
380 // ULXR_TRACE(ULXR_PCHAR("ConnHeaderLine:"));
381
382 if (*buffer == '\r')
383 setConnectionState(ConnPendingCR);
384
385 else if (*buffer == '\n')
386 {
387 if (pimpl->header_buffer.length() == 0)
388 setConnectionState(ConnSwitchToBody);
389 else
390 setConnectionState(ConnPendingHeaderLine);
391 }
392
393 else
394 pimpl->header_buffer += *buffer;
395
396 ++buffer;
397 --len;
398 break;
399
400 case ConnSwitchToBody:
401 machine_switchToBody(buffer, len, chunk_start, chunk_cursor);
402 break;
403
404 case ConnChunkHeader:
405 {
406 ULXR_TRACE(ULXR_PCHAR("ConnChunkHeader:"));
407
408 char c = *buffer;
409 if (c != '\n' && c != '\r')
410 pimpl->chunk_data += c;
411
412 ++buffer;
413 --len;
414
415 if (c == '\n')
416 {
417 char* pStop;
418 pimpl->chunk_size = std::strtol(pimpl->chunk_data.c_str(), &pStop, 16);
419 ULXR_TRACE(ULXR_PCHAR("chunk with ")
420 << pimpl->chunk_size
421 << ULXR_PCHAR(" bytes announced"));
422
423 if ( *pStop != ' '
424 && *pStop != 0
425 && *pStop != ';')
426 {
427 setConnectionState(ConnError);
428 throw ConnectionException(SystemError, ulxr_i18n(ULXR_PCHAR("chunk size is followed by a bad character: ")) + *pStop, 500);
429 }
430
431 if (getContentLength() > 0)
432 setRemainingContentLength(getRemainingContentLength() - pimpl->chunk_size);
433 else if(getContentLength() == 0)
434 setRemainingContentLength(pimpl->chunk_size);
435
436 if (pimpl->chunk_size < 1) // chunk size == 0 terminates data block
437 {
438 pimpl->chunk_in_header = false;
439 setConnectionState(State(ConnHeaderLine));
440 }
441 else
442 setConnectionState(State(ConnChunkBody));
443 }
444
445 if (len <= 0)
446 {
447 len = chunk_cursor - chunk_start;
448 buffer = chunk_start;
449 if (len != 0)
450 return ConnBody; // fake regular body
451 else
452 return State(ConnChunkHeader);
453 }
454 }
455 break;
456
457 case ConnChunkBodySkip:
458 buffer++;
459 len--;
460 if (--pimpl->chunk_body_skip <= 0)
461 {
462 pimpl->chunk_data.clear();
463 setConnectionState(State(ConnChunkHeader));
464 }
465 break;
466
467 case ConnChunkBody:
468 ULXR_TRACE(ULXR_PCHAR("ConnChunkBody:"));
469 while (pimpl->chunk_size > 0 && len > 0)
470 {
471 *chunk_cursor++ = *buffer++;
472 --pimpl->chunk_size;
473 --len;
474 }
475
476 if (pimpl->chunk_size <= 0)
477 {
478 pimpl->chunk_body_skip = 2;
479 setConnectionState(State(ConnChunkBodySkip));
480 }
481 break;
482
483 case ConnChunkTerminated:
484 ULXR_TRACE(ULXR_PCHAR("ConnChunkTerminated:"));
485 return State(ConnChunkTerminated);
486 /*break; */
487
488 case ConnBody:
489 ULXR_TRACE(ULXR_PCHAR("ConnBody:"));
490 return ConnBody;
491 /*break; */
492
493 case ConnError:
494 ULXR_TRACE(ULXR_PCHAR("ConnError:"));
495 return ConnError;
496 /*break; */
497
498 default:
499 setConnectionState(ConnError);
500 throw ConnectionException(SystemError, ulxr_i18n(ULXR_PCHAR("connectionMachine(): unknown state")), 500);
501 }
502 }
503
504 if (getConnectionState() == ConnSwitchToBody)
505 machine_switchToBody(buffer, len, chunk_start, chunk_cursor);
506
507 ULXR_TRACE(ULXR_PCHAR("/connectionMachine"));
508
509 if (pimpl->bChunkedEncoding)
510 {
511 len = chunk_cursor - chunk_start;
512 buffer = chunk_start;
513 if (len != 0)
514 return ConnBody;
515 }
516
517 return getConnectionState();
518 }
519
520
machine_switchToBody(char * & buffer,long & len,char * & chunk_start,char * & chunk_cursor)521 void HttpProtocol::machine_switchToBody(char * &buffer,
522 long &len,
523 char * &chunk_start,
524 char * &chunk_cursor)
525 {
526 ULXR_TRACE(ULXR_PCHAR("ConnSwitchToBody:"));
527 if (pimpl->chunk_in_header)
528 {
529 if (!checkContinue())
530 {
531 if (hasHttpProperty(ULXR_PCHAR("transfer-encoding")))
532 {
533 CppString sEncoding = getHttpProperty(ULXR_PCHAR("transfer-encoding"));
534 if (sEncoding == ULXR_PCHAR("chunked"))
535 {
536 setRemainingContentLength(-1);
537 setContentLength(-1);
538 ULXR_TRACE(ULXR_PCHAR("have chunked transfer encoding"));
539 pimpl->bChunkedEncoding = true;
540 pimpl->chunk_size = 0;
541 pimpl->chunk_data.clear();
542 }
543 }
544
545 if (!pimpl->bChunkedEncoding)
546 {
547 if (hasHttpProperty(ULXR_PCHAR("content-length")))
548 {
549 determineContentLength();
550
551 ULXR_TRACE(ULXR_PCHAR("content_length: ") << getContentLength());
552 ULXR_TRACE(ULXR_PCHAR("len: ") << len);
553
554 if (getContentLength() >= 0)
555 setRemainingContentLength(getContentLength() - len);
556 }
557 setConnectionState(ConnBody);
558 }
559 else
560 setConnectionState(State(ConnChunkHeader));
561 }
562 }
563 else
564 {
565 len = chunk_cursor - chunk_start;
566 buffer = chunk_start;
567 setConnectionState(State(ConnChunkTerminated));
568 pimpl->chunk_terminated = true;
569 }
570
571 if (hasClosingProperty())
572 setPersistent(false);
573 else
574 setPersistent(true);
575 }
576
577
ULXR_API_IMPL(bool)578 ULXR_API_IMPL(bool) HttpProtocol::hasBytesToRead() const
579 {
580 bool b = false;
581 if (pimpl->bChunkedEncoding)
582 b = !pimpl->chunk_terminated;
583 else
584 b = getRemainingContentLength() != 0;
585
586 ULXR_TRACE(ULXR_PCHAR("hasBytesToRead: " << b));
587 return b;
588 }
589
590
ULXR_API_IMPL(void)591 ULXR_API_IMPL(void) HttpProtocol::determineContentLength()
592 {
593 ULXR_TRACE(ULXR_PCHAR("determineContentLength"));
594
595 header_property::iterator it;
596 if ((it = pimpl->headerprops.find(ULXR_PCHAR("content-length"))) != pimpl->headerprops.end() )
597 {
598 ULXR_TRACE(ULXR_PCHAR(" content-length: ") << (*it).second);
599 setContentLength(ulxr_atoi(getLatin1((*it).second).c_str()));
600 ULXR_TRACE(ULXR_PCHAR(" length: ") << getContentLength());
601 }
602 else
603 {
604 if (pimpl->bChunkedEncoding)
605 setContentLength(0); // set with next chunk header
606 else
607 throw ConnectionException(NotConformingError,
608 ulxr_i18n(ULXR_PCHAR("Content-Length of message not available")), 411);
609
610 }
611
612 setRemainingContentLength(getContentLength());
613 ULXR_TRACE(ULXR_PCHAR(" content_length: ") << getContentLength());
614 }
615
616
ULXR_API_IMPL(void)617 ULXR_API_IMPL(void)
618 HttpProtocol::sendResponseHeader(int code,
619 const CppString &phrase,
620 const CppString &type,
621 unsigned long len,
622 bool wbxml_mode)
623 {
624 // doConnect(); must already be pimpl->connected
625
626 ULXR_TRACE(ULXR_PCHAR("sendResponseHeader"));
627 char stat[40];
628 ulxr_sprintf(stat, "%d", code );
629
630 char contlen[40];
631 ulxr_sprintf(contlen, "%ld", len );
632
633 CppString ps = phrase;
634
635 std::size_t pos = 0;
636 while ((pos = ps.find('\n', pos)) != CppString::npos)
637 {
638 ps.replace(pos, 1, ULXR_PCHAR(" "));
639 pos += 1;
640 }
641
642 pos = 0;
643 while ((pos = ps.find(ULXR_CHAR('\r'), pos)) != CppString::npos)
644 {
645 ps.replace(pos, 1, ULXR_PCHAR(" "));
646 pos += 1;
647 }
648
649 CppString http_str = (CppString) ULXR_PCHAR("HTTP/1.1 ")
650 + ULXR_GET_STRING(stat) + ULXR_PCHAR(" ") + ps
651 + ULXR_PCHAR("\r\n");
652
653 if (!isPersistent())
654 http_str += ULXR_PCHAR("Connection: Close\r\n");
655 else
656 http_str += ULXR_PCHAR("Proxy-Connection: Keep-Alive\r\n");
657
658 if (len != 0 && type.length() != 0)
659 http_str += ULXR_PCHAR("Content-Type: ") + type + ULXR_PCHAR("\r\n");
660
661 for (unsigned i = 0; i < pimpl->userTempFields.size(); ++i)
662 http_str += pimpl->userTempFields[i] + ULXR_CHAR("\r\n");
663 pimpl->userTempFields.clear();
664
665 if (hasServerCookie())
666 http_str += ULXR_PCHAR("Set-Cookie: ") + getServerCookie() + ULXR_PCHAR("\r\n");
667
668 if (isChunkedTransfer())
669 {
670 http_str += ULXR_PCHAR("Transfer-Encoding: chunked\r\n");
671 #ifdef ULXR_DEBUG_OUTPUT
672 http_str += ULXR_PCHAR("X-Content-Length: ") + ULXR_GET_STRING(contlen) + ULXR_PCHAR("\r\n");
673 #endif
674 }
675 else
676 http_str += ULXR_PCHAR("Content-Length: ") + ULXR_GET_STRING(contlen) + ULXR_PCHAR("\r\n");
677
678 if (!wbxml_mode)
679 {
680 http_str += ULXR_PCHAR("X-Powered-By: ") + getUserAgent() + ULXR_PCHAR("\r\n")
681 + ULXR_PCHAR("Server: ") + pimpl->hostname + ULXR_PCHAR("\r\n")
682 + ULXR_PCHAR("Date: ") + getDateStr() + ULXR_PCHAR("\r\n");
683 }
684
685 http_str += ULXR_PCHAR("\r\n"); // empty line at end of header
686
687 ULXR_DOUT_HTTP(ULXR_PCHAR("resp: \n") << http_str.c_str());
688
689 #ifdef ULXR_UNICODE
690 Cpp8BitString utf = unicodeToUtf8(http_str);
691 writeRaw(utf.data(), utf.length());
692 #else
693 writeRaw(http_str.data(), http_str.length());
694 #endif
695 }
696
697
ULXR_API_IMPL(void)698 ULXR_API_IMPL(void) HttpProtocol::enableConnect(bool enable)
699 {
700 ULXR_TRACE(ULXR_PCHAR("enableConnect ") << enable);
701 pimpl->useconnect = enable;
702 }
703
704
ULXR_API_IMPL(bool)705 ULXR_API_IMPL(bool) HttpProtocol::isConnectEnabled() const
706 {
707 ULXR_TRACE(ULXR_PCHAR("isConnectEnabled ") << pimpl->useconnect);
708 return pimpl->useconnect;
709 }
710
711
ULXR_API_IMPL(bool)712 ULXR_API_IMPL(bool) HttpProtocol::isConnected() const
713 {
714 ULXR_TRACE(ULXR_PCHAR("ispimpl->connected ") << pimpl->connected);
715 return pimpl->connected;
716 }
717
718
ULXR_API_IMPL(void)719 ULXR_API_IMPL(void) HttpProtocol::awaitConnect()
720 {
721 ULXR_TRACE(ULXR_PCHAR("awaitConnect"));
722
723 char buffer[ULXR_RECV_BUFFER_SIZE];
724 char *buff_ptr;
725 bool done = false;
726 long readed;
727 while (!done && hasBytesToRead()
728 && ((readed = readRaw(buffer, sizeof(buffer))) > 0) )
729 {
730 buff_ptr = buffer;
731 ULXR_TRACE(ULXR_PCHAR("loop"));
732
733 if (readed > 0)
734 {
735 State state = connectionMachine(buff_ptr, readed);
736 if (state == ConnError)
737 {
738 ULXR_TRACE(ULXR_PCHAR("ConnError"));
739 done = true;
740 throw ConnectionException(TransportError, ulxr_i18n(ULXR_PCHAR("network problem occured")), 400);
741 }
742
743 else if (state == ConnSwitchToBody)
744 {
745 ULXR_TRACE(ULXR_PCHAR("ConnSwitchToBody"));
746 done = true;
747 }
748
749 else if (state == ConnBody)
750 {
751 ULXR_TRACE(ULXR_PCHAR("ConnBody"));
752 done = true;
753 }
754 }
755 }
756
757 CppString head_version;
758 unsigned head_status = 500;
759 CppString head_phrase = ULXR_PCHAR("Internal error");
760 splitHeaderLine(head_version, head_status, head_phrase);
761
762 if (head_status != 200)
763 throw ConnectionException(TransportError, head_phrase, head_status);
764
765 pimpl->connected = true;
766 ULXR_TRACE(ULXR_PCHAR("awaitConnect: pimpl->connected"));
767 }
768
769
ULXR_API_IMPL(void)770 ULXR_API_IMPL(void) HttpProtocol::tryConnect()
771 {
772 ULXR_TRACE(ULXR_PCHAR("performConnect"));
773
774 char ports[40];
775 ulxr_sprintf(ports, ":%d", pimpl->hostport);
776 CppString resource = pimpl->hostname + ULXR_GET_STRING(ports);
777 CppString http_str = ULXR_PCHAR("CONNECT ") + resource + ULXR_PCHAR(" HTTP/1.1\r\n");
778
779 http_str += ULXR_PCHAR("User-Agent: ") + getUserAgent() + ULXR_PCHAR("\r\n");
780 http_str += ULXR_PCHAR("Proxy-Connection: Keep-Alive\r\n");
781 http_str += ULXR_PCHAR("Host: ") + pimpl->hostname + ULXR_PCHAR("\r\n");
782
783 if (pimpl->proxy_user.length() + pimpl->proxy_pass.length() != 0)
784 http_str += ULXR_PCHAR("Proxy-Authorization: Basic ")
785 + encodeBase64(pimpl->proxy_user + ULXR_PCHAR(":") + pimpl->proxy_pass);
786
787 http_str += ULXR_PCHAR("\r\n"); // empty line at end of header
788
789 ULXR_DOUT_HTTP(ULXR_PCHAR("connect: \n") << http_str.c_str());
790
791 #ifdef ULXR_UNICODE
792 Cpp8BitString utf = unicodeToUtf8(http_str);
793 writeRaw(utf.data(), utf.length());
794 #else
795 writeRaw(http_str.data(), http_str.length());
796 #endif
797 }
798
799
ULXR_API_IMPL(void)800 ULXR_API_IMPL(void) HttpProtocol::doConnect()
801 {
802 if (isConnectEnabled() && !isConnected())
803 {
804 resetConnection();
805 tryConnect();
806 awaitConnect();
807 resetConnection();
808 }
809 }
810
811
ULXR_API_IMPL(void)812 ULXR_API_IMPL(void)
813 HttpProtocol::sendRequestHeader(const CppString &method,
814 const CppString &in_resource,
815 const CppString &type,
816 unsigned long len,
817 bool wbxml_mode)
818 {
819 doConnect();
820 pimpl->bChunkedEncoding = false;
821 ULXR_TRACE(ULXR_PCHAR("sendRequestHeader"));
822 char contlen[40];
823 ulxr_sprintf(contlen, "%ld", len );
824
825 char ports[40];
826 ulxr_sprintf(ports, "%d", pimpl->hostport);
827 CppString resource = ULXR_PCHAR("http://") + pimpl->hostname + ULXR_PCHAR(":") + ULXR_GET_STRING(ports) + in_resource;
828 CppString http_str = method + ULXR_PCHAR(" ") + resource + ULXR_PCHAR(" HTTP/1.1\r\n");
829 http_str += ULXR_PCHAR("Host: ") + pimpl->hostname + ULXR_PCHAR("\r\n");
830
831 if(!wbxml_mode)
832 http_str += ULXR_PCHAR("User-Agent: ") + getUserAgent() + ULXR_PCHAR("\r\n");
833
834 if (pimpl->proxy_user.length() + pimpl->proxy_pass.length() != 0)
835 http_str += ULXR_PCHAR("Proxy-Authorization: Basic ")
836 + encodeBase64(pimpl->proxy_user + ULXR_PCHAR(":") + pimpl->proxy_pass);
837
838 if (!isPersistent())
839 http_str += ULXR_PCHAR("Connection: Close\r\n");
840 else
841 http_str += ULXR_PCHAR("Proxy-Connection: Keep-Alive\r\n");
842
843 if (len != 0 && type.length() != 0)
844 http_str += ULXR_PCHAR("Content-Type: ") + type + ULXR_PCHAR("\r\n");
845
846 for (unsigned i = 0; i < pimpl->userTempFields.size(); ++i)
847 http_str += pimpl->userTempFields[i] + ULXR_CHAR("\r\n");
848 pimpl->userTempFields.clear();
849
850 if(!wbxml_mode)
851 http_str += ULXR_PCHAR("Date: ") + getDateStr() + ULXR_PCHAR("\r\n");
852
853 if (isChunkedTransfer())
854 {
855 http_str += ULXR_PCHAR("Transfer-Encoding: chunked\r\n");
856 #ifdef ULXR_DEBUG_OUTPUT
857 http_str += ULXR_PCHAR("X-Content-Length: ") + ULXR_GET_STRING(contlen) + ULXR_PCHAR("\r\n");
858 #endif
859 }
860 else
861 http_str += ULXR_PCHAR("Content-Length: ") + ULXR_GET_STRING(contlen) + ULXR_PCHAR("\r\n");
862
863 if (hasClientCookie())
864 http_str += ULXR_PCHAR("Cookie: ") + getClientCookie() + ULXR_PCHAR("\r\n");
865
866 http_str += ULXR_PCHAR("\r\n"); // empty line at end of header
867
868 ULXR_DOUT_HTTP(ULXR_PCHAR("req: \n") << http_str.c_str());
869
870 #ifdef ULXR_UNICODE
871 Cpp8BitString utf = unicodeToUtf8(http_str);
872 writeRaw(utf.data(), utf.length());
873 #else
874 writeRaw(http_str.data(), http_str.length());
875 #endif
876 };
877
878
ULXR_API_IMPL(CppString)879 ULXR_API_IMPL(CppString) HttpProtocol::getDateStr()
880 {
881 ULXR_TRACE(ULXR_PCHAR("getDateStr"));
882 time_t tm;
883 time(&tm);
884
885 #ifndef HAVE_CTIME_R
886
887 #ifndef ULXR_OMIT_REENTRANT_PROTECTOR // todo: optionally replace with ctime_r
888 Mutex::Locker lock(ctimeMutex);
889 #endif
890
891 char * ct = ulxr_ctime(&tm);
892 CppString s = ULXR_GET_STRING(ct); // "\n" already included!
893
894 #else
895
896 char buff[40];
897 char * ct = ::ctime_r(&tm, buff);
898 CppString s = ULXR_GET_STRING(ct); // "\n" already included!
899
900 #endif
901
902 s.erase(s.length()-1); // remove it
903 return s;
904 }
905
906
ULXR_API_IMPL(void)907 ULXR_API_IMPL(void)
908 HttpProtocol::sendNegativeResponse(int status,
909 const CppString &phrase,
910 const CppString &info)
911 {
912 ULXR_TRACE(ULXR_PCHAR("sendNegativeResponse"));
913
914 // doConnect(); must already be pimpl->connected
915
916 char stat[40];
917 ulxr_sprintf(stat, "%d", status );
918
919 CppString msg = ulxr_i18n(ULXR_PCHAR("<html>")
920 ULXR_PCHAR("<head><title>Error occured</title></head>")
921 ULXR_PCHAR("<body>")
922 ULXR_PCHAR("<b>Sorry, error occured: ")) + ULXR_GET_STRING(stat)
923 + ULXR_PCHAR(", ") + phrase;
924
925 if (info.length() != 0)
926 msg += ULXR_PCHAR("<br />") + info;
927
928 msg += ulxr_i18n(ULXR_PCHAR("</b>")
929 ULXR_PCHAR("<hr /><p>")
930 ULXR_PCHAR("This cute little server is powered by")
931 ULXR_PCHAR(" <a href=\"http://ulxmlrpcpp.sourceforge.net\">"));
932
933 msg += ULXR_GET_STRING(ULXR_PACKAGE)
934 + ULXR_PCHAR("/v") + ULXR_GET_STRING(ULXR_VERSION)
935 + ULXR_PCHAR("</a>")
936 + ULXR_PCHAR("</p>")
937 ULXR_PCHAR("</body>")
938 ULXR_PCHAR("</html>");
939
940 ULXR_DOUT_RESP(ULXR_PCHAR("msg:\n") << msg);
941
942 #ifdef ULXR_UNICODE
943 Cpp8BitString utf = unicodeToUtf8(msg);
944 sendResponseHeader(status, phrase, ULXR_PCHAR("text/html"), utf.length());
945 writeRaw(utf.data(), utf.length());
946 #else
947 sendResponseHeader(status, phrase, ULXR_PCHAR("text/html"), msg.length());
948 writeRaw(msg.data(), msg.length());
949 #endif
950 }
951
952
ULXR_API_IMPL(void)953 ULXR_API_IMPL(void) HttpProtocol::sendRpcResponse(const MethodResponse &resp, bool wbxml_mode)
954 {
955 ULXR_TRACE(ULXR_PCHAR("sendRpcResponse"));
956
957 // doConnect(); must already be pimpl->connected
958
959 if (wbxml_mode)
960 {
961 std::string xml = resp.getWbXml();
962 ULXR_DOUT_XML(binaryDebugOutput(xml));
963 sendResponseHeader(200, ULXR_PCHAR("OK"), ULXR_PCHAR("application/x-wbxml-ulxr"), xml.length(), wbxml_mode);
964 writeBody(xml.data(), xml.length());
965 }
966 else
967 {
968 CppString xml = resp.getXml(0)+ULXR_PCHAR("\n");
969 ULXR_DOUT_XML(xml);
970
971 #ifdef ULXR_UNICODE
972 Cpp8BitString utf = unicodeToUtf8(xml);
973 sendResponseHeader(200, ULXR_PCHAR("OK"), ULXR_PCHAR("text/xml"), utf.length(), wbxml_mode);
974 writeBody(utf.data(), utf.length());
975 #else
976 sendResponseHeader(200, ULXR_PCHAR("OK"), ULXR_PCHAR("text/xml"), xml.length(), wbxml_mode);
977 writeBody(xml.data(), xml.length());
978 #endif
979
980 }
981 }
982
ULXR_API_IMPL(void)983 ULXR_API_IMPL(void) HttpProtocol::writeChunk(const char *data, unsigned long len)
984 {
985 if (!isChunkedTransfer())
986 throw ConnectionException(NotConformingError,
987 ulxr_i18n(ULXR_PCHAR("Protocol is not prepared for chunked encoding: ")), 400);
988
989 if (len != 0)
990 {
991 char stat[40];
992 ulxr_sprintf(stat, "%lx", len);
993 ULXR_TRACE(ULXR_PCHAR("HttpProtocol::writeChunk() chunk with 0x")
994 << ULXR_GET_STRING(stat)
995 << ULXR_PCHAR(" bytes"));
996 writeRaw(stat, strlen(stat));
997 writeRaw("\r\n", 2);
998 writeRaw(data, len);
999 writeRaw("\r\n", 2);
1000 }
1001 else
1002 {
1003 ULXR_TRACE(ULXR_PCHAR("HttpProtocol::writeChunk() last chunk with 0 bytes"));
1004 writeRaw("0\r\n\r\n", 5); // terminator
1005 }
1006 }
1007
1008
ULXR_API_IMPL(void)1009 ULXR_API_IMPL(void) HttpProtocol::writeBody(const char *data, unsigned long len)
1010 {
1011 if (!isChunkedTransfer())
1012 writeRaw(data, len);
1013 else
1014 {
1015 writeChunk(data, len);
1016 writeChunk(data, 0);
1017 }
1018 }
1019
1020
ULXR_API_IMPL(void)1021 ULXR_API_IMPL(void) HttpProtocol::sendRpcCall(const MethodCall &call,
1022 const CppString &resource,
1023 bool wbxml_mode)
1024 {
1025 ULXR_TRACE(ULXR_PCHAR("sendRpcCall"));
1026 doConnect();
1027
1028 if (wbxml_mode)
1029 {
1030 std::string xml = call.getWbXml();
1031 ULXR_DOUT_XML(binaryDebugOutput(xml));
1032 sendRequestHeader(ULXR_PCHAR("POST"), resource, ULXR_PCHAR("application/x-wbxml-ulxr"), xml.length(), wbxml_mode);
1033 writeBody(xml.data(), xml.length());
1034 }
1035 else
1036 {
1037 CppString xml = call.getXml(0)+ULXR_PCHAR("\n");
1038 ULXR_DOUT_XML(xml);
1039
1040 #ifdef ULXR_UNICODE
1041 Cpp8BitString utf = unicodeToUtf8(xml);
1042 sendRequestHeader(ULXR_PCHAR("POST"), resource, ULXR_PCHAR("text/xml"), utf.length(), wbxml_mode);
1043 writeBody(utf.data(), utf.length());
1044 #else
1045 sendRequestHeader(ULXR_PCHAR("POST"), resource, ULXR_PCHAR("text/xml"), xml.length(), wbxml_mode);
1046 writeBody(xml.data(), xml.length());
1047 #endif
1048
1049 }
1050 };
1051
1052
ULXR_API_IMPL(bool)1053 ULXR_API_IMPL(bool) HttpProtocol::responseStatus(CppString &phrase) const
1054 {
1055 ULXR_TRACE(ULXR_PCHAR("responseStatus"));
1056
1057 CppString s = stripWS(getFirstHeaderLine());
1058 if (s.length() == 0)
1059 {
1060 s = ulxr_i18n(ULXR_PCHAR("No connection status available"));
1061 return false;
1062 }
1063
1064 std::size_t pos = s.find(' ');
1065 if (pos != CppString::npos) // skip version
1066 s.erase(0, pos+1);
1067 else
1068 s = ULXR_PCHAR("");
1069
1070 CppString stat;
1071 s = stripWS(s);
1072 pos = s.find(ULXR_CHAR(' '));
1073 if (pos != CppString::npos)
1074 {
1075 stat = s.substr(0, pos);
1076 s.erase(0, pos+1);
1077 }
1078 else
1079 {
1080 stat = s;
1081 s = ULXR_PCHAR("");
1082 }
1083
1084 phrase = stripWS(s);
1085
1086 return stat == ULXR_PCHAR("200");
1087 }
1088
1089
ULXR_API_IMPL(bool)1090 ULXR_API_IMPL(bool) HttpProtocol::determineClosing(const CppString &http_ver)
1091 {
1092 ULXR_TRACE(ULXR_PCHAR("determineClosing"));
1093 if ( http_ver == ULXR_PCHAR("0.9")
1094 || http_ver == ULXR_PCHAR("1.0"))
1095 {
1096 if (hasHttpProperty(ULXR_PCHAR("connection")))
1097 {
1098 CppString s = getHttpProperty(ULXR_PCHAR("connection"));
1099 makeLower(s);
1100 return !(s == ULXR_PCHAR("keep-alive"));
1101 }
1102 ULXR_TRACE(ULXR_PCHAR("determineClosing: true"));
1103 return true; // close by default
1104 }
1105 else // 1.1 and later
1106 {
1107 return hasClosingProperty();
1108 /*
1109 ULXR_TRACE(ULXR_PCHAR("determineClosing: false"));
1110 return false; // keep open by default
1111 */
1112 }
1113 /*return true; avoids warning */
1114 }
1115
1116
ULXR_API_IMPL(bool)1117 ULXR_API_IMPL(bool) HttpProtocol::getUserPass(CppString &user,
1118 CppString &pass) const
1119 {
1120 ULXR_TRACE(ULXR_PCHAR("getUserPass"));
1121 user = ULXR_PCHAR("");
1122 pass = ULXR_PCHAR("");
1123
1124 if (hasHttpProperty(ULXR_PCHAR("authorization")) )
1125 {
1126 CppString auth = getHttpProperty(ULXR_PCHAR("authorization"));
1127
1128 ULXR_TRACE(ULXR_PCHAR("getUserPass: ") + auth);
1129 ULXR_TRACE(ULXR_PCHAR("getUserPass: basic?"));
1130
1131 // only know basic auth
1132 CppString auth_id = auth.substr(0, 6);
1133 makeLower(auth_id);
1134 if (auth_id != ULXR_PCHAR("basic "))
1135 return false;
1136
1137 auth.erase(0, 6);
1138 auth = decodeBase64(auth);
1139 ULXR_TRACE(ULXR_PCHAR("getUserPass: ':'? ") + auth);
1140 std::size_t pos = auth.find(':');
1141 if (pos != CppString::npos)
1142 {
1143 user = stripWS(auth.substr(0, pos));
1144 pass = stripWS(auth.substr(pos+1));
1145 ULXR_TRACE(ULXR_PCHAR("getUserPass: user=") +user + ULXR_PCHAR(", pass=")+pass);
1146 return true;
1147 }
1148 }
1149
1150 return false;
1151 }
1152
1153
ULXR_API_IMPL(void)1154 ULXR_API_IMPL(void) HttpProtocol::rejectAuthentication(const CppString &realm)
1155 {
1156 ULXR_TRACE(ULXR_PCHAR("rejectAuthentication: ") + realm);
1157 addOneTimeHttpField(ULXR_PCHAR("WWW-Authenticate"),
1158 ULXR_PCHAR("Basic realm=\"") + realm +ULXR_PCHAR("\""));
1159 sendNegativeResponse(401, ULXR_PCHAR("Authentication required for realm \"")+ realm + ULXR_PCHAR("\""));
1160 }
1161
1162
ULXR_API_IMPL(void)1163 ULXR_API_IMPL(void) HttpProtocol::addOneTimeHttpField(const CppString &name, const CppString &value)
1164 {
1165 ULXR_TRACE(ULXR_PCHAR("addOneTimeHttpField: ") + name + ULXR_PCHAR(": ") + value);
1166 pimpl->userTempFields.push_back(stripWS(name) + ULXR_PCHAR(": ") + stripWS(value));
1167 }
1168
1169
ULXR_API_IMPL(void)1170 ULXR_API_IMPL(void) HttpProtocol::setMessageAuthentication(const CppString &user,
1171 const CppString &pass)
1172 {
1173 ULXR_TRACE(ULXR_PCHAR("setMessageAuthentication"));
1174 CppString s = ULXR_PCHAR("Basic ");
1175 s += encodeBase64(user + ULXR_PCHAR(":") + pass);
1176 addOneTimeHttpField(ULXR_PCHAR("Authorization"), s);
1177 }
1178
1179
ULXR_API_IMPL(void)1180 ULXR_API_IMPL(void) HttpProtocol::setProxyAuthentication(const CppString &user,
1181 const CppString &pass)
1182 {
1183 ULXR_TRACE(ULXR_PCHAR("setProxyAuthentication"));
1184 pimpl->proxy_user = user;
1185 pimpl->proxy_pass = pass;
1186 }
1187
1188
ULXR_API_IMPL(void)1189 ULXR_API_IMPL(void) HttpProtocol::setTransmitOnly()
1190 {
1191 ULXR_TRACE(ULXR_PCHAR("setTransmitOnly"));
1192 addOneTimeHttpField(ULXR_PCHAR("X-TransmitOnly"), ULXR_PCHAR("true"));
1193 }
1194
1195
ULXR_API_IMPL(bool)1196 ULXR_API_IMPL(bool) HttpProtocol::isTransmitOnly()
1197 {
1198 ULXR_TRACE(ULXR_PCHAR("isTransmitOnly"));
1199 return hasHttpProperty(ULXR_PCHAR("X-TransmitOnly"))
1200 && (getHttpProperty(ULXR_PCHAR("X-TransmitOnly")) == ULXR_PCHAR("true"));
1201 }
1202
1203
ULXR_API_IMPL(CppString)1204 ULXR_API_IMPL(CppString) HttpProtocol::getProtocolName()
1205 {
1206 return ULXR_PCHAR("http");
1207 }
1208
1209
hasCookie() const1210 bool HttpProtocol::hasCookie() const
1211 {
1212 bool b = !pimpl->cookies.empty();
1213 ULXR_TRACE(ULXR_PCHAR("hasCookie: ") << b);
1214 return b;
1215 }
1216
1217
setCookie(const CppString & in_cont)1218 void HttpProtocol::setCookie(const CppString &in_cont)
1219 {
1220 ULXR_TRACE(ULXR_PCHAR("setCookie: ") << in_cont);
1221 CppString cont = in_cont;
1222 std::size_t uEnd = cont.find(';');
1223 while (uEnd != CppString::npos)
1224 {
1225 CppString sKV = cont.substr(0, uEnd);
1226 cont.erase(0, uEnd+1);
1227 std::size_t uEq = sKV.find('=');
1228 if (uEq != CppString::npos)
1229 {
1230 CppString sKey = stripWS(sKV.substr(0, uEq));
1231 CppString sVal = stripWS(sKV.substr(uEq+1));
1232 ULXR_TRACE(ULXR_PCHAR("setCookie: ") << sKey << ULXR_PCHAR(" ") << sVal);
1233 pimpl->cookies[sKey] = sVal;
1234 }
1235 uEnd = cont.find(';');
1236 }
1237
1238 std::size_t uEq = cont.find('=');
1239 if (uEq != CppString::npos)
1240 {
1241 CppString sKey = stripWS(cont.substr(0, uEq));
1242 CppString sVal = stripWS(cont.substr(uEq+1));
1243 ULXR_TRACE(ULXR_PCHAR("setCookie: ") << sKey << ULXR_PCHAR(" ") << sVal);
1244 pimpl->cookies[sKey] = sVal;
1245 }
1246 }
1247
1248
getCookie() const1249 CppString HttpProtocol::getCookie() const
1250 {
1251 CppString ret;
1252 for (std::map<CppString, CppString>::const_iterator iCookie = pimpl->cookies.begin();
1253 iCookie != pimpl->cookies.end();
1254 ++iCookie)
1255 {
1256 if (iCookie != pimpl->cookies.begin())
1257 ret += ULXR_PCHAR("; ");
1258 ret += (*iCookie).first + ULXR_PCHAR("=") + (*iCookie).second;
1259 }
1260 ULXR_TRACE(ULXR_PCHAR("getCookie: ") << ret);
1261 return ret;
1262 }
1263
1264
ULXR_API_IMPL(void)1265 ULXR_API_IMPL(void) HttpProtocol::setAcceptCookies(bool bAccept)
1266 {
1267 ULXR_TRACE(ULXR_PCHAR("setAcceptCookies: ") << bAccept);
1268 pimpl->bAcceptcookies = bAccept;
1269 }
1270
1271
ULXR_API_IMPL(bool)1272 ULXR_API_IMPL(bool) HttpProtocol::isAcceptCookies() const
1273 {
1274 ULXR_TRACE(ULXR_PCHAR("isAcceptCookies: ") << pimpl->bAcceptcookies);
1275 return pimpl->bAcceptcookies;
1276 }
1277
1278
ULXR_API_IMPL(void)1279 ULXR_API_IMPL(void) HttpProtocol::setServerCookie(const CppString &cookie)
1280 {
1281 ULXR_TRACE(ULXR_PCHAR("setServerCookie: ") << cookie);
1282 pimpl->serverCookie = cookie;
1283 }
1284
1285
ULXR_API_IMPL(CppString)1286 ULXR_API_IMPL(CppString) HttpProtocol::getServerCookie() const
1287 {
1288 ULXR_TRACE(ULXR_PCHAR("getServerCookie: ") << pimpl->serverCookie);
1289 return pimpl->serverCookie;
1290 }
1291
1292
ULXR_API_IMPL(bool)1293 ULXR_API_IMPL(bool) HttpProtocol::hasServerCookie() const
1294 {
1295 bool b = pimpl->serverCookie.length() != 0;
1296 ULXR_TRACE(ULXR_PCHAR("hasServerCookie: ") << b);
1297 return b;
1298 }
1299
1300
ULXR_API_IMPL(void)1301 ULXR_API_IMPL(void) HttpProtocol::setClientCookie(const CppString &cookie)
1302 {
1303 ULXR_TRACE(ULXR_PCHAR("setClientCookie: ") << cookie);
1304 pimpl->clientCookie = cookie;
1305 }
1306
1307
ULXR_API_IMPL(CppString)1308 ULXR_API_IMPL(CppString) HttpProtocol::getClientCookie() const
1309 {
1310 ULXR_TRACE(ULXR_PCHAR("getClientCookie: ") << pimpl->clientCookie);
1311 return pimpl->clientCookie;
1312 }
1313
1314
ULXR_API_IMPL(bool)1315 ULXR_API_IMPL(bool) HttpProtocol::hasClientCookie() const
1316 {
1317 bool b = pimpl->clientCookie.length() != 0;
1318 ULXR_TRACE(ULXR_PCHAR("hasClientCookie: ") << b);
1319 return b;
1320 }
1321
1322
ULXR_API_IMPL(void)1323 ULXR_API_IMPL(void) HttpProtocol::setUserAgent(const CppString &ua)
1324 {
1325 pimpl->useragent = ua;
1326 }
1327
1328
ULXR_API_IMPL(CppString)1329 ULXR_API_IMPL(CppString) HttpProtocol::getUserAgent() const
1330 {
1331 return pimpl->useragent;
1332 }
1333
1334
ULXR_API_IMPL(CppString)1335 ULXR_API_IMPL(CppString) HttpProtocol::getFirstHeaderLine() const
1336 {
1337 return pimpl->header_firstline;
1338 }
1339
1340
ULXR_API_IMPL(void)1341 ULXR_API_IMPL(void)
1342 HttpProtocol::splitHeaderLine(CppString &head_version, unsigned &head_status, CppString &head_phrase)
1343 {
1344 head_version = ULXR_PCHAR("");
1345 head_status = 500;
1346 head_phrase = ULXR_PCHAR("Internal error");
1347
1348 CppString s = stripWS(getFirstHeaderLine());
1349 std::size_t pos = s.find(' ');
1350 if (pos != CppString::npos)
1351 {
1352 head_version = s.substr(0, pos);
1353 s.erase(0, pos+1);
1354 }
1355 else
1356 {
1357 head_version = s;
1358 s = ULXR_PCHAR("");
1359 }
1360 pos = head_version.find('/');
1361 if (pos != CppString::npos)
1362 head_version.erase(0, pos+1);
1363
1364 CppString stat;
1365 s = stripWS(s);
1366 pos = s.find(' ');
1367 if (pos != CppString::npos)
1368 {
1369 stat = s.substr(0, pos);
1370 s.erase(0, pos+1);
1371 }
1372 else
1373 {
1374 stat = s;
1375 s = ULXR_PCHAR("");
1376 }
1377 head_status = ulxr_atoi(getLatin1(stat).c_str());
1378
1379 s = stripWS(s);
1380 head_phrase = s;
1381 }
1382
1383
ULXR_API_IMPL(void)1384 ULXR_API_IMPL(void) HttpProtocol::setChunkedTransfer(bool chunked)
1385 {
1386 ULXR_TRACE(ULXR_PCHAR("setChunkedTransfer() ") << chunked);
1387 pimpl->chunked_block = chunked;
1388 }
1389
1390
ULXR_API_IMPL(bool)1391 ULXR_API_IMPL(bool) HttpProtocol::isChunkedTransfer() const
1392 {
1393 ULXR_TRACE(ULXR_PCHAR("isChunkedTransfer() ") << pimpl->chunked_block);
1394 return pimpl->chunked_block;
1395 }
1396
1397
1398 } // namespace ulxr
1399
1400