1 // distribution boxbackup-0.11_trunk_2979 (svn version: 2979)
2 // Box Backup, http://www.boxbackup.org/
3 //
4 // Copyright (c) 2003-2010, Ben Summers and contributors.
5 // All rights reserved.
6 //
7 // Note that this project uses mixed licensing. Any file with this license
8 // attached, or where the code LICENSE-DUAL appears on the first line, falls
9 // under this license. See the file COPYING.txt for more information.
10 //
11 // This file is dual licensed. You may use and distribute it providing that you
12 // comply EITHER with the terms of the BSD license, OR the GPL license. It is
13 // not necessary to comply with both licenses, only one.
14 //
15 // The BSD license option follows:
16 //
17 // Redistribution and use in source and binary forms, with or without
18 // modification, are permitted provided that the following conditions are met:
19 //
20 // 1. Redistributions of source code must retain the above copyright
21 // notice, this list of conditions and the following disclaimer.
22 //
23 // 2. Redistributions in binary form must reproduce the above copyright
24 // notice, this list of conditions and the following disclaimer in the
25 // documentation and/or other materials provided with the distribution.
26 //
27 // 3. Neither the name of the Box Backup nor the names of its contributors may
28 // be used to endorse or promote products derived from this software without
29 // specific prior written permission.
30 //
31 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
32 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
33 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
34 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
35 // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
36 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
37 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
38 // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
39 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
40 // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
41 //
42 // [http://en.wikipedia.org/wiki/BSD_licenses#3-clause_license_.28.22New_BSD_License.22.29]
43 //
44 // The GPL license option follows:
45 //
46 // This program is free software; you can redistribute it and/or
47 // modify it under the terms of the GNU General Public License
48 // as published by the Free Software Foundation; either version 2
49 // of the License, or (at your option) any later version.
50 //
51 // This program is distributed in the hope that it will be useful,
52 // but WITHOUT ANY WARRANTY; without even the implied warranty of
53 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
54 // GNU General Public License for more details.
55 //
56 // You should have received a copy of the GNU General Public License
57 // along with this program; if not, write to the Free Software
58 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
59 //
60 // [http://www.gnu.org/licenses/old-licenses/gpl-2.0.html#SEC4]
61 // --------------------------------------------------------------------------
62 //
63 // File
64 // Name: HTTPRequest.cpp
65 // Purpose: Request object for HTTP connections
66 // Created: 26/3/04
67 //
68 // --------------------------------------------------------------------------
69
70 #include "Box.h"
71
72 #include <string.h>
73 #include <strings.h>
74 #include <stdlib.h>
75 #include <stdio.h>
76
77 #include "HTTPRequest.h"
78 #include "HTTPResponse.h"
79 #include "HTTPQueryDecoder.h"
80 #include "autogen_HTTPException.h"
81 #include "IOStream.h"
82 #include "IOStreamGetLine.h"
83 #include "Logging.h"
84
85 #include "MemLeakFindOn.h"
86
87 #define MAX_CONTENT_SIZE (128*1024)
88
89 #define ENSURE_COOKIE_JAR_ALLOCATED \
90 if(mpCookies == 0) {mpCookies = new CookieJar_t;}
91
92
93
94 // --------------------------------------------------------------------------
95 //
96 // Function
97 // Name: HTTPRequest::HTTPRequest()
98 // Purpose: Constructor
99 // Created: 26/3/04
100 //
101 // --------------------------------------------------------------------------
HTTPRequest()102 HTTPRequest::HTTPRequest()
103 : mMethod(Method_UNINITIALISED),
104 mHostPort(80), // default if not specified
105 mHTTPVersion(0),
106 mContentLength(-1),
107 mpCookies(0),
108 mClientKeepAliveRequested(false),
109 mExpectContinue(false),
110 mpStreamToReadFrom(NULL)
111 {
112 }
113
114
115 // --------------------------------------------------------------------------
116 //
117 // Function
118 // Name: HTTPRequest::HTTPRequest(enum Method,
119 // const std::string&)
120 // Purpose: Alternate constructor for hand-crafted requests
121 // Created: 03/01/09
122 //
123 // --------------------------------------------------------------------------
HTTPRequest(enum Method method,const std::string & rURI)124 HTTPRequest::HTTPRequest(enum Method method, const std::string& rURI)
125 : mMethod(method),
126 mRequestURI(rURI),
127 mHostPort(80), // default if not specified
128 mHTTPVersion(HTTPVersion_1_1),
129 mContentLength(-1),
130 mpCookies(0),
131 mClientKeepAliveRequested(false),
132 mExpectContinue(false),
133 mpStreamToReadFrom(NULL)
134 {
135 }
136
137
138
139 // --------------------------------------------------------------------------
140 //
141 // Function
142 // Name: HTTPRequest::~HTTPRequest()
143 // Purpose: Destructor
144 // Created: 26/3/04
145 //
146 // --------------------------------------------------------------------------
~HTTPRequest()147 HTTPRequest::~HTTPRequest()
148 {
149 // Clean up any cookies
150 if(mpCookies != 0)
151 {
152 delete mpCookies;
153 mpCookies = 0;
154 }
155 }
156
157
158 // --------------------------------------------------------------------------
159 //
160 // Function
161 // Name: HTTPRequest::Receive(IOStreamGetLine &, int)
162 // Purpose: Read the request from an IOStreamGetLine (and
163 // attached stream).
164 // Returns false if there was no valid request,
165 // probably due to a kept-alive connection closing.
166 // Created: 26/3/04
167 //
168 // --------------------------------------------------------------------------
Receive(IOStreamGetLine & rGetLine,int Timeout)169 bool HTTPRequest::Receive(IOStreamGetLine &rGetLine, int Timeout)
170 {
171 // Check caller's logic
172 if(mMethod != Method_UNINITIALISED)
173 {
174 THROW_EXCEPTION(HTTPException, RequestAlreadyBeenRead)
175 }
176
177 // Read the first line, which is of a different format to the rest of the lines
178 std::string requestLine;
179 if(!rGetLine.GetLine(requestLine, false /* no preprocessing */, Timeout))
180 {
181 // Didn't get the request line, probably end of connection which had been kept alive
182 return false;
183 }
184 BOX_TRACE("Request line: " << requestLine);
185
186 // Check the method
187 size_t p = 0; // current position in string
188 p = requestLine.find(' '); // end of first word
189
190 if (p == std::string::npos)
191 {
192 // No terminating space, looks bad
193 p = requestLine.size();
194 }
195 else
196 {
197 mHttpVerb = requestLine.substr(0, p);
198 if (mHttpVerb == "GET")
199 {
200 mMethod = Method_GET;
201 }
202 else if (mHttpVerb == "HEAD")
203 {
204 mMethod = Method_HEAD;
205 }
206 else if (mHttpVerb == "POST")
207 {
208 mMethod = Method_POST;
209 }
210 else if (mHttpVerb == "PUT")
211 {
212 mMethod = Method_PUT;
213 }
214 else
215 {
216 mMethod = Method_UNKNOWN;
217 }
218 }
219
220 // Skip spaces to find URI
221 const char *requestLinePtr = requestLine.c_str();
222 while(requestLinePtr[p] != '\0' && requestLinePtr[p] == ' ')
223 {
224 ++p;
225 }
226
227 // Check there's a URI following...
228 if(requestLinePtr[p] == '\0')
229 {
230 // Didn't get the request line, probably end of connection which had been kept alive
231 return false;
232 }
233
234 // Read the URI, unescaping any %XX hex codes
235 while(requestLinePtr[p] != ' ' && requestLinePtr[p] != '\0')
236 {
237 // End of URI, on to query string?
238 if(requestLinePtr[p] == '?')
239 {
240 // Put the rest into the query string, without escaping anything
241 ++p;
242 while(requestLinePtr[p] != ' ' && requestLinePtr[p] != '\0')
243 {
244 mQueryString += requestLinePtr[p];
245 ++p;
246 }
247 break;
248 }
249 // Needs unescaping?
250 else if(requestLinePtr[p] == '+')
251 {
252 mRequestURI += ' ';
253 }
254 else if(requestLinePtr[p] == '%')
255 {
256 // Be tolerant about this... bad things are silently accepted,
257 // rather than throwing an error.
258 char code[4] = {0,0,0,0};
259 code[0] = requestLinePtr[++p];
260 if(code[0] != '\0')
261 {
262 code[1] = requestLinePtr[++p];
263 }
264
265 // Convert into a char code
266 long c = ::strtol(code, NULL, 16);
267
268 // Accept it?
269 if(c > 0 && c <= 255)
270 {
271 mRequestURI += (char)c;
272 }
273 }
274 else
275 {
276 // Simple copy of character
277 mRequestURI += requestLinePtr[p];
278 }
279
280 ++p;
281 }
282
283 // End of URL?
284 if(requestLinePtr[p] == '\0')
285 {
286 // Assume HTTP 0.9
287 mHTTPVersion = HTTPVersion_0_9;
288 }
289 else
290 {
291 // Skip any more spaces
292 while(requestLinePtr[p] != '\0' && requestLinePtr[p] == ' ')
293 {
294 ++p;
295 }
296
297 // Check to see if there's the right string next...
298 if(::strncmp(requestLinePtr + p, "HTTP/", 5) == 0)
299 {
300 // Find the version numbers
301 int major, minor;
302 if(::sscanf(requestLinePtr + p + 5, "%d.%d", &major, &minor) != 2)
303 {
304 THROW_EXCEPTION(HTTPException, BadRequest)
305 }
306
307 // Store version
308 mHTTPVersion = (major * HTTPVersion__MajorMultiplier) + minor;
309 }
310 else
311 {
312 // Not good -- wrong string found
313 THROW_EXCEPTION(HTTPException, BadRequest)
314 }
315 }
316
317 BOX_TRACE("HTTPRequest: method=" << mMethod << ", uri=" <<
318 mRequestURI << ", version=" << mHTTPVersion);
319
320 // If HTTP 1.1 or greater, assume keep-alive
321 if(mHTTPVersion >= HTTPVersion_1_1)
322 {
323 mClientKeepAliveRequested = true;
324 }
325
326 // Decode query string?
327 if((mMethod == Method_GET || mMethod == Method_HEAD) && !mQueryString.empty())
328 {
329 HTTPQueryDecoder decoder(mQuery);
330 decoder.DecodeChunk(mQueryString.c_str(), mQueryString.size());
331 decoder.Finish();
332 }
333
334 // Now parse the headers
335 ParseHeaders(rGetLine, Timeout);
336
337 std::string expected;
338 if (GetHeader("Expect", &expected))
339 {
340 if (expected == "100-continue")
341 {
342 mExpectContinue = true;
343 }
344 }
345
346 // Parse form data?
347 if(mMethod == Method_POST && mContentLength >= 0)
348 {
349 // Too long? Don't allow people to be nasty by sending lots of data
350 if(mContentLength > MAX_CONTENT_SIZE)
351 {
352 THROW_EXCEPTION(HTTPException, POSTContentTooLong)
353 }
354
355 // Some data in the request to follow, parsing it bit by bit
356 HTTPQueryDecoder decoder(mQuery);
357 // Don't forget any data left in the GetLine object
358 int fromBuffer = rGetLine.GetSizeOfBufferedData();
359 if(fromBuffer > mContentLength) fromBuffer = mContentLength;
360 if(fromBuffer > 0)
361 {
362 BOX_TRACE("Decoding " << fromBuffer << " bytes of "
363 "data from getline buffer");
364 decoder.DecodeChunk((const char *)rGetLine.GetBufferedData(), fromBuffer);
365 // And tell the getline object to ignore the data we just used
366 rGetLine.IgnoreBufferedData(fromBuffer);
367 }
368 // Then read any more data, as required
369 int bytesToGo = mContentLength - fromBuffer;
370 while(bytesToGo > 0)
371 {
372 char buf[4096];
373 int toRead = sizeof(buf);
374 if(toRead > bytesToGo) toRead = bytesToGo;
375 IOStream &rstream(rGetLine.GetUnderlyingStream());
376 int r = rstream.Read(buf, toRead, Timeout);
377 if(r == 0)
378 {
379 // Timeout, just error
380 THROW_EXCEPTION(HTTPException, RequestReadFailed)
381 }
382 decoder.DecodeChunk(buf, r);
383 bytesToGo -= r;
384 }
385 // Finish off
386 decoder.Finish();
387 }
388 else if (mContentLength > 0)
389 {
390 IOStream::pos_type bytesToCopy = rGetLine.GetSizeOfBufferedData();
391 if (bytesToCopy > mContentLength)
392 {
393 bytesToCopy = mContentLength;
394 }
395 Write(rGetLine.GetBufferedData(), bytesToCopy);
396 SetForReading();
397 mpStreamToReadFrom = &(rGetLine.GetUnderlyingStream());
398 }
399
400 return true;
401 }
402
ReadContent(IOStream & rStreamToWriteTo)403 void HTTPRequest::ReadContent(IOStream& rStreamToWriteTo)
404 {
405 Seek(0, SeekType_Absolute);
406
407 CopyStreamTo(rStreamToWriteTo);
408 IOStream::pos_type bytesCopied = GetSize();
409
410 while (bytesCopied < mContentLength)
411 {
412 char buffer[1024];
413 IOStream::pos_type bytesToCopy = sizeof(buffer);
414 if (bytesToCopy > mContentLength - bytesCopied)
415 {
416 bytesToCopy = mContentLength - bytesCopied;
417 }
418 bytesToCopy = mpStreamToReadFrom->Read(buffer, bytesToCopy);
419 rStreamToWriteTo.Write(buffer, bytesToCopy);
420 bytesCopied += bytesToCopy;
421 }
422 }
423
424 // --------------------------------------------------------------------------
425 //
426 // Function
427 // Name: HTTPRequest::Send(IOStream &, int)
428 // Purpose: Write the request to an IOStream using HTTP.
429 // Created: 03/01/09
430 //
431 // --------------------------------------------------------------------------
Send(IOStream & rStream,int Timeout,bool ExpectContinue)432 bool HTTPRequest::Send(IOStream &rStream, int Timeout, bool ExpectContinue)
433 {
434 switch (mMethod)
435 {
436 case Method_UNINITIALISED:
437 THROW_EXCEPTION(HTTPException, RequestNotInitialised); break;
438 case Method_UNKNOWN:
439 THROW_EXCEPTION(HTTPException, BadRequest); break;
440 case Method_GET:
441 rStream.Write("GET"); break;
442 case Method_HEAD:
443 rStream.Write("HEAD"); break;
444 case Method_POST:
445 rStream.Write("POST"); break;
446 case Method_PUT:
447 rStream.Write("PUT"); break;
448 }
449
450 rStream.Write(" ");
451 rStream.Write(mRequestURI.c_str());
452 rStream.Write(" ");
453
454 switch (mHTTPVersion)
455 {
456 case HTTPVersion_0_9: rStream.Write("HTTP/0.9"); break;
457 case HTTPVersion_1_0: rStream.Write("HTTP/1.0"); break;
458 case HTTPVersion_1_1: rStream.Write("HTTP/1.1"); break;
459 default:
460 THROW_EXCEPTION(HTTPException, NotImplemented);
461 }
462
463 rStream.Write("\n");
464 std::ostringstream oss;
465
466 if (mContentLength != -1)
467 {
468 oss << "Content-Length: " << mContentLength << "\n";
469 }
470
471 if (mContentType != "")
472 {
473 oss << "Content-Type: " << mContentType << "\n";
474 }
475
476 if (mHostName != "")
477 {
478 if (mHostPort != 80)
479 {
480 oss << "Host: " << mHostName << ":" << mHostPort <<
481 "\n";
482 }
483 else
484 {
485 oss << "Host: " << mHostName << "\n";
486 }
487 }
488
489 if (mpCookies)
490 {
491 THROW_EXCEPTION(HTTPException, NotImplemented);
492 }
493
494 if (mClientKeepAliveRequested)
495 {
496 oss << "Connection: keep-alive\n";
497 }
498 else
499 {
500 oss << "Connection: close\n";
501 }
502
503 for (std::vector<Header>::iterator i = mExtraHeaders.begin();
504 i != mExtraHeaders.end(); i++)
505 {
506 oss << i->first << ": " << i->second << "\n";
507 }
508
509 if (ExpectContinue)
510 {
511 oss << "Expect: 100-continue\n";
512 }
513
514 rStream.Write(oss.str().c_str());
515 rStream.Write("\n");
516
517 return true;
518 }
519
SendWithStream(IOStream & rStreamToSendTo,int Timeout,IOStream * pStreamToSend,HTTPResponse & rResponse)520 void HTTPRequest::SendWithStream(IOStream &rStreamToSendTo, int Timeout,
521 IOStream* pStreamToSend, HTTPResponse& rResponse)
522 {
523 IOStream::pos_type size = pStreamToSend->BytesLeftToRead();
524
525 if (size != IOStream::SizeOfStreamUnknown)
526 {
527 mContentLength = size;
528 }
529
530 Send(rStreamToSendTo, Timeout, true);
531
532 rResponse.Receive(rStreamToSendTo, Timeout);
533 if (rResponse.GetResponseCode() != 100)
534 {
535 // bad response, abort now
536 return;
537 }
538
539 pStreamToSend->CopyStreamTo(rStreamToSendTo, Timeout);
540
541 // receive the final response
542 rResponse.Receive(rStreamToSendTo, Timeout);
543 }
544
545 // --------------------------------------------------------------------------
546 //
547 // Function
548 // Name: HTTPRequest::ParseHeaders(IOStreamGetLine &, int)
549 // Purpose: Private. Parse the headers of the request
550 // Created: 26/3/04
551 //
552 // --------------------------------------------------------------------------
ParseHeaders(IOStreamGetLine & rGetLine,int Timeout)553 void HTTPRequest::ParseHeaders(IOStreamGetLine &rGetLine, int Timeout)
554 {
555 std::string header;
556 bool haveHeader = false;
557 while(true)
558 {
559 if(rGetLine.IsEOF())
560 {
561 // Header terminates unexpectedly
562 THROW_EXCEPTION(HTTPException, BadRequest)
563 }
564
565 std::string currentLine;
566 if(!rGetLine.GetLine(currentLine, false /* no preprocess */, Timeout))
567 {
568 // Timeout
569 THROW_EXCEPTION(HTTPException, RequestReadFailed)
570 }
571
572 // Is this a continuation of the previous line?
573 bool processHeader = haveHeader;
574 if(!currentLine.empty() && (currentLine[0] == ' ' || currentLine[0] == '\t'))
575 {
576 // A continuation, don't process anything yet
577 processHeader = false;
578 }
579 //TRACE3("%d:%d:%s\n", processHeader, haveHeader, currentLine.c_str());
580
581 // Parse the header -- this will actually process the header
582 // from the previous run around the loop.
583 if(processHeader)
584 {
585 // Find where the : is in the line
586 const char *h = header.c_str();
587 int p = 0;
588 while(h[p] != '\0' && h[p] != ':')
589 {
590 ++p;
591 }
592 // Skip white space
593 int dataStart = p + 1;
594 while(h[dataStart] == ' ' || h[dataStart] == '\t')
595 {
596 ++dataStart;
597 }
598
599 std::string header_name(ToLowerCase(std::string(h,
600 p)));
601
602 if (header_name == "content-length")
603 {
604 // Decode number
605 long len = ::strtol(h + dataStart, NULL, 10); // returns zero in error case, this is OK
606 if(len < 0) len = 0;
607 // Store
608 mContentLength = len;
609 }
610 else if (header_name == "content-type")
611 {
612 // Store rest of string as content type
613 mContentType = h + dataStart;
614 }
615 else if (header_name == "host")
616 {
617 // Store host header
618 mHostName = h + dataStart;
619
620 // Is there a port number to split off?
621 std::string::size_type colon = mHostName.find_first_of(':');
622 if(colon != std::string::npos)
623 {
624 // There's a port in the string... attempt to turn it into an int
625 mHostPort = ::strtol(mHostName.c_str() + colon + 1, 0, 10);
626
627 // Truncate the string to just the hostname
628 mHostName = mHostName.substr(0, colon);
629
630 BOX_TRACE("Host: header, hostname = " <<
631 "'" << mHostName << "', host "
632 "port = " << mHostPort);
633 }
634 }
635 else if (header_name == "cookie")
636 {
637 // Parse cookies
638 ParseCookies(header, dataStart);
639 }
640 else if (header_name == "connection")
641 {
642 // Connection header, what is required?
643 const char *v = h + dataStart;
644 if(::strcasecmp(v, "close") == 0)
645 {
646 mClientKeepAliveRequested = false;
647 }
648 else if(::strcasecmp(v, "keep-alive") == 0)
649 {
650 mClientKeepAliveRequested = true;
651 }
652 // else don't understand, just assume default for protocol version
653 }
654 else
655 {
656 mExtraHeaders.push_back(Header(header_name,
657 h + dataStart));
658 }
659
660 // Unset have header flag, as it's now been processed
661 haveHeader = false;
662 }
663
664 // Store the chunk of header the for next time round
665 if(haveHeader)
666 {
667 header += currentLine;
668 }
669 else
670 {
671 header = currentLine;
672 haveHeader = true;
673 }
674
675 // End of headers?
676 if(currentLine.empty())
677 {
678 // All done!
679 break;
680 }
681 }
682 }
683
684
685 // --------------------------------------------------------------------------
686 //
687 // Function
688 // Name: HTTPRequest::ParseCookies(const std::string &, int)
689 // Purpose: Parse the cookie header
690 // Created: 20/8/04
691 //
692 // --------------------------------------------------------------------------
ParseCookies(const std::string & rHeader,int DataStarts)693 void HTTPRequest::ParseCookies(const std::string &rHeader, int DataStarts)
694 {
695 const char *data = rHeader.c_str() + DataStarts;
696 const char *pos = data;
697 const char *itemStart = pos;
698 std::string name;
699
700 enum
701 {
702 s_NAME, s_VALUE, s_VALUE_QUOTED, s_FIND_NEXT_NAME
703 } state = s_NAME;
704
705 do
706 {
707 switch(state)
708 {
709 case s_NAME:
710 {
711 if(*pos == '=')
712 {
713 // Found the name. Store
714 name.assign(itemStart, pos - itemStart);
715 // Looking at values now
716 state = s_VALUE;
717 if((*(pos + 1)) == '"')
718 {
719 // Actually it's a quoted value, skip over that
720 ++pos;
721 state = s_VALUE_QUOTED;
722 }
723 // Record starting point for this item
724 itemStart = pos + 1;
725 }
726 }
727 break;
728
729 case s_VALUE:
730 {
731 if(*pos == ';' || *pos == ',' || *pos == '\0')
732 {
733 // Name ends
734 ENSURE_COOKIE_JAR_ALLOCATED
735 std::string value(itemStart, pos - itemStart);
736 (*mpCookies)[name] = value;
737 // And move to the waiting stage
738 state = s_FIND_NEXT_NAME;
739 }
740 }
741 break;
742
743 case s_VALUE_QUOTED:
744 {
745 if(*pos == '"')
746 {
747 // That'll do nicely, save it
748 ENSURE_COOKIE_JAR_ALLOCATED
749 std::string value(itemStart, pos - itemStart);
750 (*mpCookies)[name] = value;
751 // And move to the waiting stage
752 state = s_FIND_NEXT_NAME;
753 }
754 }
755 break;
756
757 case s_FIND_NEXT_NAME:
758 {
759 // Skip over terminators and white space to get to the next name
760 if(*pos != ';' && *pos != ',' && *pos != ' ' && *pos != '\t')
761 {
762 // Name starts here
763 itemStart = pos;
764 state = s_NAME;
765 }
766 }
767 break;
768
769 default:
770 // Ooops
771 THROW_EXCEPTION(HTTPException, Internal)
772 break;
773 }
774 }
775 while(*(pos++) != 0);
776 }
777
778
779 // --------------------------------------------------------------------------
780 //
781 // Function
782 // Name: HTTPRequest::GetCookie(const char *, std::string &) const
783 // Purpose: Fetch a cookie's value. If cookie not present, returns false
784 // and string is unaltered.
785 // Created: 20/8/04
786 //
787 // --------------------------------------------------------------------------
GetCookie(const char * CookieName,std::string & rValueOut) const788 bool HTTPRequest::GetCookie(const char *CookieName, std::string &rValueOut) const
789 {
790 // Got any cookies?
791 if(mpCookies == 0)
792 {
793 return false;
794 }
795
796 // See if it's there
797 CookieJar_t::const_iterator v(mpCookies->find(std::string(CookieName)));
798 if(v != mpCookies->end())
799 {
800 // Return the value
801 rValueOut = v->second;
802 return true;
803 }
804
805 return false;
806 }
807
808
809 // --------------------------------------------------------------------------
810 //
811 // Function
812 // Name: HTTPRequest::GetCookie(const char *)
813 // Purpose: Return a string for the given cookie, or the null string if the
814 // cookie has not been recieved.
815 // Created: 22/8/04
816 //
817 // --------------------------------------------------------------------------
GetCookie(const char * CookieName) const818 const std::string &HTTPRequest::GetCookie(const char *CookieName) const
819 {
820 static const std::string noCookie;
821
822 // Got any cookies?
823 if(mpCookies == 0)
824 {
825 return noCookie;
826 }
827
828 // See if it's there
829 CookieJar_t::const_iterator v(mpCookies->find(std::string(CookieName)));
830 if(v != mpCookies->end())
831 {
832 // Return the value
833 return v->second;
834 }
835
836 return noCookie;
837 }
838
839
840
841