DCL 3.7.4
Loading...
Searching...
No Matches
HttpCollection.cpp
Go to the documentation of this file.
1#include <dcl/Config.h>
2
3#ifdef __WINNT__
4 #include <windows.h>
5#endif
6
7#include <ctype.h>
8#include <stdlib.h>
9#include <string.h>
10
11#include <dcl/Object.h>
12
13#if __DCL_HAVE_ALLOC_DEBUG
14#undef __DCL_ALLOC_LEVEL
15#define __DCL_ALLOC_LEVEL __DCL_ALLOC_INTERNAL
16#endif
17
18#include <dcl/Numeric.h>
19
20#include <dcl/URI.h>
21#include <dcl/HttpServlet.h>
22#include <dcl/HttpCollection.h>
23#include <dcl/Array.h>
24#include <dcl/Charset.h>
27#include <dcl/Files.h>
28
29#define __DEBUG_THIS 0
30#if __DEBUG_THIS
31#define __DCL_TRACE1_N __DCL_TRACE1
32#define __DCL_TRACE2_N __DCL_TRACE2
33#define __DCL_TRACE3_N __DCL_TRACE3
34#else
35#define __DCL_TRACE1_N(fmt, arg)
36#define __DCL_TRACE2_N(fmt, arg1, arg2)
37#define __DCL_TRACE3_N(fmt, arg1, arg2, arg3)
38#endif
39
40#if __DCL_HAVE_THIS_FILE__
41#undef __THIS_FILE__
42static const char_t* __THIS_FILE__ = __T("dcl/HttpCollection.cpp");
43#endif
44
45__DCL_BEGIN_NAMESPACE
46
48 const ByteString& _contents,
49 ListedStringToStringMap& _results
50)
51{
52 ByteStringArray elements;
53 _contents.split(';', elements);
54
55 for(ByteStringArray::Iterator it = elements.begin();
56 it != elements.end(); it++
57 ) {
58 ByteStringArray pair;
59 ByteString name;
60 ByteString value;
61
62 (*it).split('=', pair);
63 ByteStringArray::Iterator itPair = pair.begin();
64
65 if (itPair != pair.end()) {
66 name = (*itPair); // .trim();
67
68 itPair++;
69 if (itPair != pair.end()) {
70 value = (*itPair); // .trim();
71 }
72
73 _results[UTF8Decoder::decode(name)] =
74 UTF8Decoder::decode(value);
75 }
76 }
77}
78
80 const ByteString& _queryString,
81 ListedStringToStringArrayMap& _results
82)
83{
85 _queryString,
86 _queryString.data() + _queryString.length(),
87 _results
88 );
89}
90
92 const char* _begin,
93 const char* _end,
94 ListedStringToStringArrayMap& _results
95)
96{
97 ByteStringArray elements;
98 ByteString::split(_begin, _end, '&', elements);
99
100 for(ByteStringArray::Iterator it = elements.begin();
101 it != elements.end(); it++
102 ) {
103 ByteStringArray pair;
104 ByteString name;
105 ByteString value;
106
107 (*it).split(L'=', pair);
108 ByteStringArray::Iterator itPair = pair.begin();
109
110 if (itPair != pair.end()) {
111 //name = URLDecoder::decode(*itPair); // .trim();
112 name = *itPair;
113 if (!name.isEmpty()) {
114 itPair++;
115 value = itPair != pair.end() ?
116 URLDecoder::decode(*itPair) : "";
117
118 (_results[UTF8Decoder::decode(name)])
119 .add(UTF8Decoder::decode(value));
120 }
121 }
122 }
123}
124
126 const char* _contentType
127)
128{
129 __DCL_ASSERT(_contentType != NULL
130 && *_contentType != '\0');
131
132 while(isspace((unsigned int)*_contentType))
133 _contentType++;
134
135 return ByteString::compareNoCase(
136 _contentType,
137 "application/x-www-form-urlencoded",
138 33
139 ) == 0;
140}
141
143 const ListedStringToStringArrayMap& _map
144)
145{
146 ByteStringBuilder sb;
147
148 for(ListedStringToStringArrayMap::ConstIterator it = _map.begin();
149 _map.end() != it; it++
150 ) {
151 if (!sb.isEmpty())
152 sb += "&";
153
154 const ByteString name = UTF8Encoder::encode((*it).key);
155 const StringArray& values = (*it).value;
156 for(size_t i = 0; i < values.size(); i++) {
157 sb += name;
158 sb += '=';
159 sb += UTF8Encoder::encode(values[i]);
160 }
161 }
162
164}
165
167
168String HttpFormData::PartHeader::toString() const
169{
170 StringBuilder sb;
171 sb.append(L"type[").append(type)
172 .append(L"], name[").append(name)
173 .append(L"], filename[").append(filename)
174 .append(L"], contentType[").append(contentType)
175 .append(L"]");
176 return sb;
177}
178
179// default file handler
180// data ignored
181
182bool HttpFormData::onFileStart(
183 const PartHeader& header,
184 void** ppCallbackData,
185 String& strCallbackError // return false 이면
186)
187{
188#ifdef __DCL_DEBUG
189 size_t* pTotalSize = new size_t;
190 __DCL_ASSERT(pTotalSize != NULL);
191
192 *pTotalSize = 0;
193
194 *ppCallbackData = pTotalSize;
195#endif
196 return true;
197}
198
199bool HttpFormData::onFileData(
200 const void* pData,
201 size_t nSize,
202 void* pCallbackData,
203 String& strCallbackError // return false 이면
204)
205{
206#ifdef __DCL_DEBUG
207 size_t* pTotalSize = (size_t*)pCallbackData;
208 *pTotalSize += nSize;
209#endif
210 return true;
211}
212
213bool HttpFormData::onFileEnd(
214 const PartHeader& header,
215 void* pCallbackData,
216 bool bDataSuccess,
217 String& strCallbackError // return false 이면
218)
219{
220#ifdef __DCL_DEBUG
221 size_t* pTotalSize = (size_t*)pCallbackData;
222
223 StringBuilder sb = L"Warning! name=\"";
224 sb += header.name + L"\" filename=\"";
225 sb += header.filename + L"\" ";
226 sb += String::valueOf(*pTotalSize) + L" bytes";
227 if (!bDataSuccess)
228 sb += L", in data error";
229 sb += L", discarded\n";
230 __DCL_TRACE0(sb.data());
231#ifdef __DCL_DEBUG_DELETE
232// MINGW64 g++ 은 overrided delete를 호출하지 않는다!
233#define delete(_p) __DCL_DEBUG_DELETE(_p)
234#endif
235 delete (pTotalSize);
236#ifdef __DCL_DEBUG_DELETE
237#undef delete
238#endif
239#endif
240 return true;
241}
242
244
245HttpFormDataDecoderException::HttpFormDataDecoderException(
246 ErrorCode _errorCode,
247 IOException* _cause
248) : Exception(_cause)
249{
250 __errorCode = _errorCode;
251}
252
253HttpFormDataDecoderException::HttpFormDataDecoderException(
254 ErrorCode _errorCode,
255 const String& _message
256) : Exception(NULL)
257{
258 __errorCode = _errorCode;
259 __message = _message;
260}
261
263{
264 StringBuilder str;
265 switch(__errorCode) {
266 case ePostReadError :
267 str = L"HTTP POST read error - See Detail Exception";
268 break;
269 case eFormDataCallbackError :
270 str = L"HttpFormData Object callback error";
271 break;
272 default :
273 __DCL_ASSERT(false);
274 }
275
276 if (!__message.isEmpty()) {
277 str += L": " + __message;
278 }
279 return str;
280}
281
283
285 size_t _bufferSize // = 4096
286)
287{
288 __input = NULL;
289 __contentLength = 0;
290 __remainder = 0;
291
292 __buffer = NULL;
293 __bufferSize = _bufferSize;
294 __begin = NULL;
295 __end = NULL;
296
297 __contentDisposition = "Content-Disposition";
298 __contentType = "Content-Type";
299 __name = "name";
300 __filename = "filename";
301
302}
303
305{
306 if (__buffer) {
307 free(__buffer);
308 }
309}
310
312 InputStream& _input,
313 const char* _contentType,
314 size_t _contentLength,
315 ListedStringToStringArrayMap& _mapForm,
316 HttpFormData& _mapFormFile
318{
319 __DCL_ASSERT(_contentType != NULL && *_contentType != '\0');
320 __DCL_ASSERT(_contentLength > 0);
321
322 __input = &_input;
323 __contentLength = _contentLength;
324 __remainder = _contentLength;
325
326 ByteString boundary = "--";
327 {
328 ByteString strOrgBoundary = getBoundary(_contentType);
329 if (strOrgBoundary.isEmpty()) {
330 appendWarning(L"Error! invalid boundary");
331 return;
332 }
333 boundary = boundary + strOrgBoundary;
334 }
335
336 __DCL_ASSERT(__bufferSize > (size_t)(boundary.length() + 2));
337
338 __DCL_TRACE1_N(L"boundary[%hs]\n", boundary.data());
339
340 if(!readInput()) {
341 appendWarning(L"Warning! Input data empty");
342 return;
343 }
344
345 bool bNextPart = getFirstBoundary(boundary);
346
347 while(bNextPart) {
348 HttpFormData::PartHeader header;
349 if (!getPartHeader(header)) {
350 appendWarning(L"Warning! not found boundary delimiter");
351 break;
352 }
353
354 __DCL_TRACE1_N(L"partHeader %ls\n", header.toString().data());
355
356 // Content-Type: multipart/mixed 이면 위치에서
357 // HttpFormDataDecoder::decode를 재귀적으로 호출한다.
358 // RFC1867에는 2개이상의 파일을 포함할 경우 multipart/mixed
359 // 를 사용한다고 되어 있으나 Microsoft-IE, Netscape Navigator
360 // 모두 그렇게 하고 있지 않고 있다.
361
362 if (header.filename.isEmpty()) {
363 // normal data
364 ByteStringBuilder value;
365
366 char* _begin = NULL;
367 char* _end = NULL;
368 DataState ds = dsNeedMoreData;
369 while((ds = getDataBlock(boundary, _begin, _end)) == dsNeedMoreData) {
370 if (_begin < _end) {
371 value.append(_begin, _end);
372 }
373
374 if (!readInput()) {
375 // EOF : data error
376 break;
377 }
378 }
379
380 if (ds == dsNeedMoreData) {
381 // 데이터 에러: EOF or too small data
382 // 더이상 데이터가 없다. 데이터 에러이다.
383 // 데이터는 무시한다.
384 String strMsg = header.name
385 + L": invalid data, discarded";
386 appendWarning(strMsg);
387 __DCL_TRACE1_N(L"%ls\n", strMsg.data());
388
389 bNextPart = false;
390 }
391 else {
392 // 정상 데이터
393 // 마지막 데이터 추가
394 if (_begin < _end) {
395 value.append(_begin, _end);
396 }
397
398 (_mapForm[header.name]).add(UTF8Decoder::decode(value));
399
400 if (ds == dsBeforeCloseBoundary)
401 bNextPart = false;
402 }
403 }
404 else {
405 // input type=file
406 void* pCallbackData = NULL;
407 String strCallbackError;
408 if (!_mapFormFile.onFileStart(
409 header,
410 &pCallbackData,
411 strCallbackError
412 )) {
413 // callback 시작에서 에러가 발생하면 decoding을 중단한다.
415 HttpFormDataDecoderException::eFormDataCallbackError,
416 strCallbackError
417 );
418 }
419
420 char* _begin = NULL;
421 char* _end = NULL;
422 DataState ds = dsNeedMoreData;
423 while((ds = getDataBlock(boundary, _begin, _end)) == dsNeedMoreData) {
424 if (_begin < _end) {
425 // 데이터가 있으면
426 if (!_mapFormFile.onFileData(
427 _begin,
428 _end - _begin,
429 pCallbackData,
430 strCallbackError
431 )) {
433 HttpFormDataDecoderException::eFormDataCallbackError,
434 strCallbackError
435 );
436 }
437 }
438
439 try {
440 if (!readInput()) {
441 // EOF : data error
442 break;
443 }
444 }
446 if (!_mapFormFile.onFileEnd(
447 header,
448 pCallbackData,
449 false,
450 strCallbackError
451 )) {
452 __DCL_TRACE1(L"HttpFormData::onFileEnd: %ls\n", strCallbackError.data());
453 }
454
455 throw e;
456 }
457 } // end of while
458
459 if (ds == dsNeedMoreData) {
460 // 데이터 에러: EOF or too small data
461 // 더이상 데이터가 없다. 데이터 에러이다.
462 // 읽혀진 데이터는 버린다.
463 String strMsg = header.name
464 + L":\"" + header.filename
465 + L"\": invalid data, discarded";
466
467 appendWarning(strMsg);
468 __DCL_TRACE1_N(L"%ls\n", strMsg.data());
469
470 if (!_mapFormFile.onFileEnd(
471 header,
472 pCallbackData,
473 false,
474 strCallbackError
475 )) {
476 __DCL_TRACE1(L"HttpFormData::onFileEnd: %ls\n", strCallbackError.data());
477 }
478
479 bNextPart = false;
480 }
481 else {
482 // 정상 데이터
483 if (_begin < _end) {
484 if (!_mapFormFile.onFileData(
485 _begin,
486 _end - _begin,
487 pCallbackData,
488 strCallbackError
489 )) {
491 HttpFormDataDecoderException::eFormDataCallbackError,
492 strCallbackError
493 );
494 }
495 }
496
497 if (!_mapFormFile.onFileEnd(
498 header,
499 pCallbackData,
500 true,
501 strCallbackError
502 )) {
504 HttpFormDataDecoderException::eFormDataCallbackError,
505 strCallbackError
506 );
507 }
508
509 if (ds == dsBeforeCloseBoundary)
510 bNextPart = false;
511 }
512 }
513 }
514}
515
516#undef CR
517#undef LF
518#define CR '\r'
519#define LF '\n'
520
521// CRLF을 찾으면 CR의 포인터를, 없으면 NULL을 반환한다.
522inline char* __find_CRLF(
523 char* _begin, char* _end
524)
525{
526 _end--;
527 while (_begin < _end) {
528 if (*_begin == CR && *(_begin + 1) == LF) {
529 return _begin;
530 }
531 _begin++;
532 }
533 return NULL;
534}
535
536inline char* __find_CHAR(
537 char* _begin, char* _end, char _ch
538)
539{
540 while (_begin < _end) {
541 if (*_begin == _ch) {
542 return _begin;
543 }
544 _begin++;
545 }
546 return NULL;
547}
548
549HttpFormDataDecoder::DataState
550HttpFormDataDecoder::getDataBlock(
551 const ByteString& _boundary,
552 char*& _begin,
553 char*& _end
554)
555{
556 __DCL_ASSERT(__buffer != NULL);
557 __DCL_ASSERT(__begin <= __end);
558
559 // 시작 시점에서 버퍼는 적어도
560 // boundary.length() + 2 (close boundary size) 보다 작으면
561 // 데이터가 유효하지 않다.
562 if (!((__begin + _boundary.length() + 2) <= __end)) {
563 return dsNeedMoreData;
564 }
565
566 // CRLF를 확인한 후 CRLF의 이후가 boundary이면
567 // CRLF까지를 _end로
568 _end = _begin = __begin;
569 char* atCR = NULL;
570 while((atCR = __find_CRLF(_end, __end)) != NULL) {
571 // CRLF를 찾았다.
572 // CRLF 다음이 boundary이면 atCR까지이고,
573 // 그렇지 않으면 다음 CRLF를 찾는다.
574 _end = atCR;
575 char* afterCRLF = atCR + 2;
576 __DCL_ASSERT(afterCRLF <= __end);
577 if ((afterCRLF + _boundary.length()) <= __end) {
578 if (!memcmp(_boundary.data(), afterCRLF, _boundary.length())) {
579 DataState dsReturn = dsBeforeNextBoundary;
580 afterCRLF += _boundary.length();
581 if (afterCRLF + 2 <= __end
582 && !memcmp(afterCRLF, "--", 2)) {
583 // close boundary
584 dsReturn = dsBeforeCloseBoundary;
585 }
586
587 // boundary 이후에 CRLF가 있다. skip한다.
588 char* p = __find_CRLF(afterCRLF, __end);
589 if (p) {
590 afterCRLF = p + 2;
591 }
592
593 __DCL_ASSERT(afterCRLF <= __end);
594 __begin = afterCRLF;
595 return dsReturn;
596 }
597 _end = afterCRLF;
598 // 다음 CRLF를 찾는다.
599 }
600 else {
601 // 버퍼의 데이터가 작다. CRLF 찾는것을 종료한다.
602 break;
603 }
604 }
605
606 __DCL_ASSERT(__begin <= _end);
607 if (__begin == _end) {
608 // 한번도 CRLF를 못 찾았다.
609 _end = __end - 1;
610 if (*_end != CR)
611 _end++;
612 }
613
614 __begin = _end;
615 return dsNeedMoreData;
616}
617
618bool HttpFormDataDecoder::getLine(
619 char*& _begin, char*& _end
620)
621{
622 __DCL_ASSERT(__buffer != NULL);
623 char* atCR = __find_CRLF(__begin, __end);
624 if (!atCR) {
625 return false;
626 }
627
628 _begin = __begin;
629 _end = __begin = atCR;
630
631 // __begin은 CRLF의 다음으로
632 __begin += 2;
633
634 while (_begin < _end) {
635 if (!isspace(*_begin)) {
636 break;
637 }
638 _begin++;
639 }
640
641 return true;
642}
643
644bool HttpFormDataDecoder::getFirstBoundary(
645 const ByteString& _boundary
646)
647{
648 char* _begin;
649 char* _end;
650 while(getLine(_begin, _end)) {
651 if (((_begin + _boundary.length()) <= _end)
652 && (!memcmp(_boundary.data(), _begin, _boundary.length()))) {
653 // check end boundary
654 _begin += _boundary.length();
655 if (!ByteString::compare(_begin, "--", 2)) {
656 // data error
657 return false;
658 }
659 return true;
660 }
661 }
662 // data error
663 return false;
664}
665
666#define EQUAL_STR(str, p) (!(str).compareNoCase((p), str.length()))
667bool HttpFormDataDecoder::getPartHeader(
668 HttpFormData::PartHeader& header
670{
671 for( ; ; ) {
672 char* _begin;
673 char* _end;
674 if (!getLine(_begin, _end)) {
675 if (!readInput())
676 return false;
677 if (!getLine(_begin, _end))
678 return false;
679 }
680
681 if (!(_begin < _end)) {
682 // 헤더를 모두 읽었다
683 break;
684 }
685
686 char* _value = __find_CHAR(_begin, _end, ':');
687 if (!_value) {
688 // invalid line
689 continue;
690 }
691 while(isspace((byte_t)*(++_value)));
692
693 if (EQUAL_STR(__contentDisposition, _begin)) {
694 _begin = _value;
695 while(_begin < _end) {
696 char* _next = __find_CHAR(_begin, _end, ';');
697 if (!_next) {
698 _next = _end;
699 }
700
701 _value = __find_CHAR(_begin, _next, '=');
702 if (_value) {
703 while(isspace((byte_t)*(++_value)));
704
705 if (EQUAL_STR(__name, _begin)) {
706 header.name = UTF8Decoder::decode(_value, _next - _value).trim(L"\"");
707 }
708 else if (EQUAL_STR(__filename, _begin)) {
709 header.filename = UTF8Decoder::decode(_value, _next - _value).trim(L"\"");
710 // IE는 절대경로를 포함하고 netscape는 basename이다.
711 size_t index = header.filename.lastIndexOf(L'\\');
712 if (index != (size_t)-1) {
713 header.filename = header.filename.mid(index + 1);
714 }
715 }
716 else {
717 String s = String::format(L"unknown property [%ls]",
718 UTF8Decoder::decode(_begin, _end - _begin).data());
719 appendWarning(s);
720 __DCL_TRACE1_N(L"%ls\n", s.data());
721 }
722 }
723 else {
724 header.type = UTF8Decoder::decode(_begin, _next - _begin);
725 }
726
727 if (_next < _end) {
728 while (isspace((byte_t) * (++_next)));
729 }
730 _begin = _next;
731 }
732 }
733 else if (EQUAL_STR(__contentType, _begin)) {
734 header.contentType = UTF8Decoder::decode(_value, _end - _value);
735 }
736 else {
737 String s = String::format(L"Invalid header [%ls]",
738 UTF8Decoder::decode(_begin, _end - _begin).data());
739 appendWarning(s);
740 __DCL_TRACE1_N(L"%ls\n", s.data());
741 }
742 }
743
744 return true;
745}
746
747bool HttpFormDataDecoder::readInput()
749{
750 if (__remainder) {
751 try {
752 if (!__buffer) {
753 __buffer = (char*)malloc(__bufferSize + 1);
754 __DCL_ASSERT(__buffer != NULL);
755 *(__buffer + __bufferSize) = '\0';
756
757 __begin = __buffer;
758 __end = __buffer;
759 }
760
761 size_t n = __end - __begin;
762 if (n) {
763 memmove(__buffer, __begin, n);
764 __begin = __buffer;
765 __end = __buffer + n;
766 }
767 else {
768 // 캐시된 데이터가 없다. 전체를 다시 읽어야 한다.
769 __begin = __buffer;
770 __end = __buffer;
771 }
772
773 size_t nCanRead = __bufferSize - n;
774 if (__remainder < nCanRead)
775 nCanRead = __remainder;
776
777 size_t nRead = __input->read(__end, nCanRead);
778 __end += nRead;
779 __DCL_TRACE2_N(L"CanRead: %d, Read: %d\n", nCanRead, nRead);
780 __remainder -= nRead;
781
782 return true;
783 }
784 catch(IOException* eCause) {
785 throw new HttpFormDataDecoderException(
786 HttpFormDataDecoderException::ePostReadError,
787 eCause
788 );
789 }
790 }
791 return false;
792}
793
794void HttpFormDataDecoder::appendWarning(const String& _warning)
795{
796 if (!__warnings.isEmpty())
797 __warnings += L'\n';
798
799 __warnings += _warning;
800}
801
802// static members
803ByteString HttpFormDataDecoder::getBoundary(
804 const char* _contentType
805)
806{
807 __DCL_ASSERT(_contentType != NULL && *_contentType != '\0');
808
809 ByteStringBuilder sb;
810 const char* p = strstr(_contentType, "boundary");
811 if (p) {
812 p += 8; // strlen("boundary");
813 p = strchr(p, '=');
814 if (p) {
815 while(isspace((byte_t)*(++p)))
816 ;
817 sb = p;
818 sb.trim();
819 }
820 }
821
822 return sb;
823}
824
825bool HttpFormDataDecoder::isValidType(const char* _contentType)
826{
827 __DCL_ASSERT(_contentType != NULL
828 && *_contentType != '\0');
829
830 while(isspace((byte_t)*_contentType))
831 _contentType++;
832
833 return ByteString::compareNoCase(
834 _contentType,
835 "multipart/form-data",
836 19
837 ) == 0;
838}
839
841
842BufferedHttpFormData::FileInfo::FileInfo()
843{
844}
845
846#undef __V
847#define __V() ((PointerArray*)__handle)
848BufferedHttpFormData::FileInfo&
849BufferedHttpFormData::FileInfoArray::operator[] (size_t _index)
850{
851 __DCL_ASSERT(_index < __V()->size());
852
853 return *((FileInfo*)((*__V())[_index]));
854}
855
856size_t BufferedHttpFormData::FileInfoArray::size() const
857{
858 __DCL_ASSERT(__handle != NULL);
859
860 return __V()->size();
861}
862
863bool BufferedHttpFormData::FileInfoArray::isEmpty() const
864{
865 __DCL_ASSERT(__handle != NULL);
866
867 return __V()->isEmpty();
868}
869
870BufferedHttpFormData::FileInfoArray::FileInfoArray(const String& _name)
871{
872 __handle = new PointerArray();
873 __name = _name;
874
875 __DCL_ASSERT(__handle != NULL);
876}
877
878BufferedHttpFormData::FileInfoArray::FileInfoArray(const FileInfo& src)
879{
880 // 결코 불려져서는 안됨
881 __DCL_ASSERT(false);
882}
883
884BufferedHttpFormData::FileInfoArray::~FileInfoArray()
885{
886 __DCL_ASSERT(__handle != NULL);
887 PointerArray* p = __V();
888 PointerArray& v = *p;
889 for(size_t i = 0; i < v.size(); i++)
890 delete (FileInfo*)v[i];
891 v.clear();
892 delete p;
893}
894
895void BufferedHttpFormData::FileInfoArray::add(FileInfo* pNewItem)
896{
897 __DCL_ASSERT(pNewItem != NULL);
898 __V()->add(pNewItem);
899}
900
902{
903 __handle = new PointerArray();
904 __DCL_ASSERT(__handle != NULL);
905}
906
908{
909 __DCL_ASSERT(__handle != NULL);
910 PointerArray* p = __V();
911 PointerArray& v = *p;
912 for(size_t i = 0; i < v.size(); i++)
913 delete (FileInfoArray*)v[i];
914 v.clear();
915 delete p;
916}
917
919{
920 __DCL_ASSERT(__handle != NULL);
921 return __V()->size();
922}
923
925{
926 __DCL_ASSERT(__handle != NULL);
927
928 return __V()->isEmpty();
929}
930
931BufferedHttpFormData::FileInfoArray&
933{
934 __DCL_ASSERT(_index < __V()->size());
935 return *((FileInfoArray*)((*__V())[_index]));
936}
937
938BufferedHttpFormData::FileInfoArray&
939BufferedHttpFormData::byName(const wchar_t* _name)
941{
942 __DCL_ASSERT(_name != NULL && *_name != '\0');
943
944 FileInfoArray* pV = NULL;
945 PointerArray& v = *(PointerArray*)__handle;
946 for(size_t i = 0; i < v.size(); i++) {
947 pV = (FileInfoArray*)(v[i]);
948 if (pV->__name == _name)
949 return *pV;
950 }
951
952 pV = new FileInfoArray(_name);
953 v.add(pV);
954 return *pV;
955}
956
957void BufferedHttpFormData::insert(
958 const String& _name,
959 FileInfo* pNewItem
960)
961{
962 __DCL_ASSERT(!_name.isEmpty());
963
964 FileInfoArray& v = byName(_name);
965 v.add(pNewItem);
966}
967
970 const PartHeader& header,
971 void** ppCallbackData,
972 String& strCallbackError // return false 이면
973)
974{
976 __DCL_ASSERT(output != NULL);
977
978 *ppCallbackData = output;
979
980 return true;
981}
982
984 const void* pData,
985 size_t nSize,
986 void* pCallbackData,
987 String& strCallbackError // return false 이면
988)
989{
990 BytesOutputStream* output = (BytesOutputStream*)pCallbackData;
991 __DCL_ASSERT(output != NULL);
992
993 try {
994 output->write(pData, nSize);
995 }
996 catch(IOException* e) {
997 delete output;
998
999 strCallbackError = e->toString();
1000 e->destroy();
1001 return false;
1002 }
1003
1004 return true;
1005}
1006
1008 const PartHeader& header,
1009 void* pCallbackData,
1010 bool bDataSuccess,
1011 String& strCallbackError // return false 이면
1012)
1013{
1014 BytesOutputStream* output = (BytesOutputStream*)pCallbackData;
1015 __DCL_ASSERT(output != NULL);
1016
1017 if (bDataSuccess) {
1018 FileInfo* pInfo = new FileInfo;
1019
1020 pInfo->filename = header.filename;
1021 pInfo->contentType = header.contentType;
1022 pInfo->fileData = output->toByteString();
1023
1024 delete output;
1025
1026 insert(header.name, pInfo);
1027 }
1028
1029 return true;
1030}
1031
1033
1034#undef __V
1035#define __V() ((PointerArray*)__handle)
1036
1037StoredHttpFormData::FileInfo::FileInfo()
1038{
1039 fileSize = 0;
1040}
1041
1042StoredHttpFormData::FileInfo::FileInfo(const FileInfo& str)
1043{
1044 __DCL_ASSERT(false);
1045}
1046
1047StoredHttpFormData::FileInfo::~FileInfo()
1048{
1049 try {
1050 if (Files::exists(tempFilename))
1051 Files::unlink(tempFilename);
1052 }
1053 catch(IOException* e) {
1054 __DCL_TRACE1(L"%ls\n", e->toString().data());
1055 e->destroy();
1056 }
1057}
1058
1059StoredHttpFormData::FileInfo&
1060StoredHttpFormData::FileInfoArray::operator[] (size_t _index)
1061{
1062 __DCL_ASSERT( _index < __V()->size());
1063
1064 return *((FileInfo*)((*__V())[_index]));
1065}
1066
1067size_t StoredHttpFormData::FileInfoArray::size() const
1068{
1069 __DCL_ASSERT(__handle != NULL);
1070 return __V()->size();
1071}
1072
1073bool StoredHttpFormData::FileInfoArray::isEmpty() const
1074{
1075 __DCL_ASSERT(__handle != NULL);
1076 return __V()->isEmpty();
1077}
1078
1079StoredHttpFormData::FileInfoArray::FileInfoArray(const String& _name)
1080{
1081 __handle = new PointerArray;
1082 __name = _name;
1083
1084 __DCL_ASSERT(__handle != NULL);
1085}
1086
1087StoredHttpFormData::FileInfoArray::FileInfoArray(const FileInfo& src)
1088{
1089 // 결코 불려져서는 안됨
1090 __DCL_ASSERT(false);
1091}
1092
1093StoredHttpFormData::FileInfoArray::~FileInfoArray()
1094{
1095 __DCL_ASSERT(__handle != NULL);
1096 PointerArray* p = __V();
1097 PointerArray& v = *p;
1098 for(size_t i = 0; i < v.size(); i++)
1099 delete (FileInfo*)v[i];
1100 v.clear();
1101 delete p;
1102}
1103
1104void StoredHttpFormData::FileInfoArray::add(FileInfo* pNewItem)
1105{
1106 __DCL_ASSERT(pNewItem != NULL);
1107 __V()->add(pNewItem);
1108}
1109
1111{
1112 __DCL_ASSERT(!strTempDir.isEmpty());
1113
1114 __tempDir = strTempDir;
1115
1116 __handle = new PointerArray;
1117 __DCL_ASSERT(__handle != NULL);
1118}
1119
1121{
1122 __DCL_ASSERT(__handle != NULL);
1123 PointerArray* p = __V();
1124 PointerArray& v = *p;
1125 for(size_t i = 0; i < v.size(); i++)
1126 delete (FileInfoArray*)v[i];
1127 v.clear();
1128 delete p;
1129}
1130
1132{
1133 __DCL_ASSERT(__handle != NULL);
1134 return __V()->size();
1135}
1136
1138{
1139 __DCL_ASSERT(__handle != NULL);
1140 return __V()->isEmpty();
1141}
1142
1143StoredHttpFormData::FileInfoArray&
1145{
1146 __DCL_ASSERT(_index < __V()->size());
1147 return *((FileInfoArray*)((*__V())[_index]));
1148}
1149
1150StoredHttpFormData::FileInfoArray&
1151StoredHttpFormData::byName(const wchar_t* _name)
1153{
1154 __DCL_ASSERT(_name != NULL && *_name != '\0');
1155
1156 FileInfoArray* pV = NULL;
1157 PointerArray& v = *(PointerArray*)__handle;
1158 for(size_t i = 0; i < v.size(); i++) {
1159 pV = (FileInfoArray*)(v[i]);
1160 if (pV->__name == _name)
1161 return *pV;
1162 }
1163
1164 pV = new FileInfoArray(_name);
1165 v.add(pV);
1166 return *pV;
1167}
1168
1169void StoredHttpFormData::insert(
1170 const String& _name,
1171 FileInfo* pNewItem
1172)
1173{
1174 __DCL_ASSERT(!_name.isEmpty());
1175
1176 FileInfoArray& v = byName(_name);
1177 v.add(pNewItem);
1178}
1179
1182{
1183public:
1185 size_t dataSize;
1187};
1188
1190 const PartHeader& header,
1191 void** ppCallbackData,
1192 String& strCallbackError // return false 이면
1193)
1194{
1195 String filename;
1196 FileOutputStream* output = NULL;
1197 try {
1198 File* pFile = File::openTempFile(
1199 __tempDir,
1200 L"dclformdata"
1201 );
1202 output = new FileOutputStream(pFile);
1203 filename = pFile->path();
1204 }
1205 catch(IOException* e) {
1206 if (!filename.isEmpty()) {
1207 try {
1208 Files::unlink(filename);
1209 }
1210 catch (IOException* e) {
1211 __DCL_TRACE1(L"%ls\n", e->toString().data());
1212 e->destroy();
1213 }
1214 }
1215 strCallbackError = e->toString();
1216 e->destroy();
1217 return false;
1218 }
1219
1221 __DCL_ASSERT(cb != NULL);
1222 cb->tempFilename = filename;
1223 cb->output = output;
1224 cb->dataSize = 0;
1225
1226 *ppCallbackData = cb;
1227
1228 return true;
1229}
1230
1232 const void* pData,
1233 size_t nSize,
1234 void* pCallbackData,
1235 String& strCallbackError // return false 이면
1236)
1237{
1238 StoredCallbackData* cb = (StoredCallbackData*)pCallbackData;
1239 __DCL_ASSERT(cb != NULL);
1240
1241 try {
1242 cb->output->write(pData, nSize);
1243 cb->dataSize += nSize;
1244 }
1245 catch(IOException* e) {
1246 try {
1247 delete cb->output;
1249 }
1250 catch(IOException* e) {
1251 __DCL_TRACE1(L"%ls\n", e->toString().data());
1252 e->destroy();
1253 }
1254
1255 delete cb;
1256
1257 strCallbackError = e->toString();
1258 e->destroy();
1259 return false;
1260 }
1261 return true;
1262}
1263
1265 const PartHeader& header,
1266 void* pCallbackData,
1267 bool bDataSuccess,
1268 String& strCallbackError // return false 이면
1269)
1270{
1271 StoredCallbackData* cb = (StoredCallbackData*)pCallbackData;
1272 __DCL_ASSERT(cb != NULL);
1273 try {
1274 delete cb->output;
1276 L"fileSize: %zd, dataSize: %zd\n",
1278 cb->dataSize
1279 );
1280 }
1281 catch(IOException* e) {
1282 try {
1284 }
1285 catch(IOException* e) {
1286 __DCL_TRACE1(L"%ls\n", e->toString().data());
1287 e->destroy();
1288 }
1289
1290 strCallbackError = e->toString();
1291 e->destroy();
1292 delete cb;
1293 return false;
1294 }
1295
1296 if (bDataSuccess) {
1297 FileInfo* pInfo = new FileInfo;
1298 __DCL_ASSERT(pInfo != NULL);
1299 pInfo->filename = header.filename;
1300 pInfo->contentType = header.contentType;
1301 pInfo->fileSize = cb->dataSize;
1302 pInfo->tempFilename = cb->tempFilename;
1303
1304 insert(header.name, pInfo);
1305 }
1306
1307 delete cb;
1308 return true;
1309}
1310
1311__DCL_END_NAMESPACE
#define __THIS_FILE__
Definition _trace.h:14
#define NULL
Definition Config.h:312
wchar_t char_t
Definition Config.h:247
unsigned char byte_t
Definition Config.h:246
#define __DCL_THROWS1(e)
Definition Config.h:152
char * __find_CHAR(char *_begin, char *_end, char _ch)
#define EQUAL_STR(str, p)
#define LF
char * __find_CRLF(char *_begin, char *_end)
#define __DCL_TRACE1_N(fmt, arg)
#define CR
#define __DCL_TRACE2_N(fmt, arg1, arg2)
#define __V()
#define __DCL_TRACE0(psz)
Definition Object.h:398
#define __DCL_TRACE1(fmt, arg1)
Definition Object.h:399
#define __DCL_ASSERT(expr)
Definition Object.h:394
#define IMPLEMENT_CLASSINFO(class_name, base_class_name)
Definition Object.h:245
#define __T(str)
Definition Object.h:60
static String decode(const char *_mbs, size_t _mbslen=(size_t) -1)
FileInfoArray & operator[](size_t _index)
virtual bool onFileStart(const PartHeader &header, void **ppCallbackData, String &strCallbackError)
FileInfoArray & byName(const wchar_t *_name)
virtual bool onFileEnd(const PartHeader &header, void *pCallbackData, bool bDataSuccess, String &strCallbackError)
virtual bool onFileData(const void *pData, size_t nSize, void *pCallbackData, String &strCallbackError)
virtual String toString() const
Definition Exception.cpp:40
virtual void destroy()
Definition Exception.cpp:74
Definition File.h:42
static File * openTempFile(const String &_dirname, const String &_prefix, unsigned int _mode=0666) __DCL_THROWS1(IOException *)
Definition File.cpp:727
const String & path() const
Definition File.h:251
static bool exists(const String &_path)
Definition Files.cpp:109
static uint64_t size(const String &_path) __DCL_THROWS1(IOException *)
Definition Files.cpp:160
static void unlink(const String &_path) __DCL_THROWS1(IOException *)
Definition Files.cpp:97
void decode(InputStream &_input, const char *_contentType, size_t _contentLength, ListedStringToStringArrayMap &_mapForm, HttpFormData &_mapFormFile) __DCL_THROWS1(HttpFormDataDecoderException *)
HttpFormDataDecoder(size_t _bufferSize=4096)
static void decode(const ByteString &_queryString, ListedStringToStringArrayMap &_results)
static bool isValidType(const char *_contentType)
static String encode(const ListedStringToStringArrayMap &_map)
virtual String toString() const
Object()
Definition Object.cpp:183
FileOutputStream * output
virtual bool onFileStart(const PartHeader &header, void **ppCallbackData, String &strCallbackError)
FileInfoArray & byName(const wchar_t *_name)
StoredHttpFormData(const String &strTempDir)
FileInfoArray & operator[](size_t _index)
virtual bool onFileData(const void *pData, size_t nSize, void *pCallbackData, String &strCallbackError)
virtual bool onFileEnd(const PartHeader &header, void *pCallbackData, bool bDataSuccess, String &strCallbackError)
static ByteString decode(const char *_begin, const char *_end)
Definition URI.cpp:46
static ByteString encode(const ByteString &_str)
Definition URI.cpp:82