DCL 4.0
Loading...
Searching...
No Matches
HttpCollection.cpp
Go to the documentation of this file.
1#include <dcl/Config.h>
2
3#if __DCL_WINDOWS
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_DEBUG
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 ByteStringArray pair;
58 ByteString name;
59 ByteString value;
60
61 (*it).split('=', pair);
62 ByteStringArray::Iterator itPair = pair.begin();
63
64 if (itPair != pair.end()) {
65 name = (*itPair); // .trim();
66
67 itPair++;
68 if (itPair != pair.end()) {
69 value = (*itPair); // .trim();
70 }
71
72 _results[UTF8Decoder::decode(name)] =
73 UTF8Decoder::decode(value);
74 }
75 }
76}
77
79 const ByteString& _queryString,
80 ListedStringToStringArrayMap& _results
81)
82{
84 _queryString,
85 _queryString.data() + _queryString.length(),
86 _results
87 );
88}
89
91 const char* _begin,
92 const char* _end,
93 ListedStringToStringArrayMap& _results
94 )
95{
96 ByteStringArray elements;
97 ByteString::split(_begin, _end, '&', elements);
98
99 for(ByteStringArray::Iterator it = elements.begin();
100 it != elements.end(); it++)
101 {
102 ByteStringArray pair;
103 ByteString name;
104 ByteString value;
105
106 (*it).split(L'=', pair);
107 ByteStringArray::Iterator itPair = pair.begin();
108
109 if (itPair != pair.end()) {
110 //name = URLDecoder::decode(*itPair); // .trim();
111 name = *itPair;
112 if (!name.isEmpty()) {
113 itPair++;
114 value = itPair != pair.end() ?
115 URLDecoder::decode(*itPair) : "";
116
117 (_results[UTF8Decoder::decode(name)])
118 .add(UTF8Decoder::decode(value));
119 }
120 }
121 }
122}
123
125 const char* _contentType
126 )
127{
128 __DCL_ASSERT(_contentType != NULL
129 && *_contentType != '\0');
130
131 while(isspace((wint_t)*_contentType))
132 _contentType++;
133
134 return ByteString::compareNoCase(
135 _contentType,
136 "application/x-www-form-urlencoded",
137 33
138 ) == 0;
139}
140
142 const ListedStringToStringArrayMap& _map
143 )
144{
145 ByteStringBuilder sb;
146
147 for(ListedStringToStringArrayMap::ConstIterator it = _map.begin();
148 _map.end() != it; it++)
149 {
150 if (!sb.isEmpty())
151 sb += "&";
152
153 const ByteString name = UTF8Encoder::encode((*it).key);
154 const StringArray& values = (*it).value;
155 for(size_t i = 0; i < values.size(); i++) {
156 sb += name;
157 sb += '=';
158 sb += UTF8Encoder::encode(values[i]);
159 }
160 }
161
163}
164
166
167String HttpFormData::PartHeader::toString() const
168{
169 StringBuilder sb;
170 sb.append(L"type[").append(type)
171 .append(L"], name[").append(name)
172 .append(L"], filename[").append(filename)
173 .append(L"], contentType[").append(contentType)
174 .append(L"]");
175 return sb;
176}
177
178// default file handler
179// data ignored
180
181bool HttpFormData::onFileStart(
182 const PartHeader& header,
183 void** ppCallbackData,
184 String& strCallbackError // return false 이면
185 )
186{
187#ifdef __DCL_DEBUG
188 size_t* pTotalSize = new size_t;
189 __DCL_ASSERT(pTotalSize != NULL);
190
191 *pTotalSize = 0;
192
193 *ppCallbackData = pTotalSize;
194#endif
195 return true;
196}
197
198bool HttpFormData::onFileData(
199 const void* pData,
200 size_t nSize,
201 void* pCallbackData,
202 String& strCallbackError // return false 이면
203 )
204{
205#ifdef __DCL_DEBUG
206 size_t* pTotalSize = (size_t*)pCallbackData;
207 *pTotalSize += nSize;
208#endif
209 return true;
210}
211
212bool HttpFormData::onFileEnd(
213 const PartHeader& header,
214 void* pCallbackData,
215 bool bDataSuccess,
216 String& strCallbackError // return false 이면
217 )
218{
219#ifdef __DCL_DEBUG
220 size_t* pTotalSize = (size_t*)pCallbackData;
221
222 StringBuilder sb = L"Warning! name=\"";
223 sb += header.name + L"\" filename=\"";
224 sb += header.filename + L"\" ";
225 sb += String::valueOf(*pTotalSize) + L" bytes";
226 if (!bDataSuccess)
227 sb += L", in data error";
228 sb += L", discarded\n";
229 __DCL_TRACE0(sb.data());
230 delete pTotalSize;
231#endif
232 return true;
233}
234
236
237HttpFormDataDecoderException::HttpFormDataDecoderException(
238 ErrorCode errorCode,
239 IOException* pDetailEx
240 )
241 : Exception(pDetailEx)
242{
243 m_errorCode = errorCode;
244}
245
246HttpFormDataDecoderException::HttpFormDataDecoderException(
247 ErrorCode errorCode,
248 const String& strMsg
249 )
250 : Exception(NULL)
251{
252 m_errorCode = errorCode;
253 m_strMsg = strMsg;
254}
255
257{
258 StringBuilder str;
259 switch(m_errorCode) {
260 case ePostReadError :
261 str = L"HTTP POST read error - See Detail Exception";
262 break;
263 case eFormDataCallbackError :
264 str = L"HttpFormData Object callback error";
265 break;
266 default :
267 __DCL_ASSERT(false);
268 }
269
270 if (!m_strMsg.isEmpty()) {
271 str += L": " + m_strMsg;
272 }
273 return str;
274}
275
277
279 size_t _bufferSize // = 4096
280 )
281{
282 __input = NULL;
283 __contentLength = 0;
284 __remainder = 0;
285
286 __buffer = NULL;
287 __bufferSize = _bufferSize;
288 __begin = NULL;
289 __end = NULL;
290
291 __contentDisposition = "Content-Disposition";
292 __contentType = "Content-Type";
293 __name = "name";
294 __filename = "filename";
295
296}
297
299{
300 if (__buffer) {
301 free(__buffer);
302 }
303}
304
306 InputStream& _input,
307 const char* _contentType,
308 size_t _contentLength,
309 ListedStringToStringArrayMap& _mapForm,
310 HttpFormData& _mapFormFile
312{
313 __DCL_ASSERT(_contentType != NULL && *_contentType != '\0');
314 __DCL_ASSERT(_contentLength > 0);
315
316 __input = &_input;
317 __contentLength = _contentLength;
318 __remainder = _contentLength;
319
320 ByteString boundary = "--";
321 {
322 ByteString strOrgBoundary = getBoundary(_contentType);
323 if (strOrgBoundary.isEmpty()) {
324 appendWarning(L"Error! invalid boundary");
325 return;
326 }
327 boundary = boundary + strOrgBoundary;
328 }
329
330 __DCL_ASSERT(__bufferSize > (size_t)(boundary.length() + 2));
331
332 __DCL_TRACE1_N(L"boundary[%s]\n", boundary.data());
333
334 if(!readInput()) {
335 appendWarning(L"Warning! Input data empty");
336 return;
337 }
338
339 bool bNextPart = getFirstBoundary(boundary);
340
341 while(bNextPart) {
342 HttpFormData::PartHeader header;
343 if (!getPartHeader(header)) {
344 appendWarning(L"Warning! not found boundary delimiter");
345 break;
346 }
347
348 __DCL_TRACE1_N(L"partHeader %ls\n", header.toString().data());
349
350 // Content-Type: multipart/mixed 이면 위치에서
351 // HttpFormDataDecoder::decode를 재귀적으로 호출한다.
352 // RFC1867에는 2개이상의 파일을 포함할 경우 multipart/mixed
353 // 를 사용한다고 되어 있으나 Microsoft-IE, Netscape Navigator
354 // 모두 그렇게 하고 있지 않고 있다.
355
356 if (header.filename.isEmpty()) {
357 // normal data
358 ByteStringBuilder value;
359
360 char* _begin = NULL;
361 char* _end = NULL;
362 DataState ds = dsNeedMoreData;
363 while((ds = getDataBlock(boundary, _begin, _end)) == dsNeedMoreData) {
364 if (_begin < _end) {
365 value.append(_begin, _end);
366 }
367
368 if (!readInput()) {
369 // EOF : data error
370 break;
371 }
372 }
373
374 if (ds == dsNeedMoreData) {
375 // 데이터 에러: EOF or too small data
376 // 더이상 데이터가 없다. 데이터 에러이다.
377 // 데이터는 무시한다.
378 String strMsg = header.name
379 + L": invalid data, discarded";
380 appendWarning(strMsg);
381 __DCL_TRACE1_N(L"%ls\n", strMsg.data());
382
383 bNextPart = false;
384 }
385 else {
386 // 정상 데이터
387 // 마지막 데이터 추가
388 if (_begin < _end) {
389 value.append(_begin, _end);
390 }
391
392 (_mapForm[header.name]).add(UTF8Decoder::decode(value));
393
394 if (ds == dsBeforeCloseBoundary)
395 bNextPart = false;
396 }
397 }
398 else {
399 // input type=file
400 void* pCallbackData = NULL;
401 String strCallbackError;
402 if (!_mapFormFile.onFileStart(
403 header,
404 &pCallbackData,
405 strCallbackError
406 )
407 ) {
408 // callback 시작에서 에러가 발생하면 decoding을 중단한다.
410 HttpFormDataDecoderException::eFormDataCallbackError,
411 strCallbackError
412 );
413 }
414
415 char* _begin = NULL;
416 char* _end = NULL;
417 DataState ds = dsNeedMoreData;
418 while((ds = getDataBlock(boundary, _begin, _end)) == dsNeedMoreData) {
419 if (_begin < _end) {
420 // 데이터가 있으면
421 if (!_mapFormFile.onFileData(
422 _begin,
423 _end - _begin,
424 pCallbackData,
425 strCallbackError
426 )) {
428 HttpFormDataDecoderException::eFormDataCallbackError,
429 strCallbackError
430 );
431 }
432 }
433
434 try {
435 if (!readInput()) {
436 // EOF : data error
437 break;
438 }
439 }
441 if (!_mapFormFile.onFileEnd(
442 header,
443 pCallbackData,
444 false,
445 strCallbackError
446 )) {
447 __DCL_TRACE1(L"HttpFormData::onFileEnd: %ls\n", strCallbackError.data());
448 }
449
450 throw e;
451 }
452 } // end of while
453
454 if (ds == dsNeedMoreData) {
455 // 데이터 에러: EOF or too small data
456 // 더이상 데이터가 없다. 데이터 에러이다.
457 // 읽혀진 데이터는 버린다.
458 String strMsg = header.name
459 + L":\"" + header.filename
460 + L"\": invalid data, discarded";
461
462 appendWarning(strMsg);
463 __DCL_TRACE1_N(L"%s\n", strMsg.data());
464
465 if (!_mapFormFile.onFileEnd(
466 header,
467 pCallbackData,
468 false,
469 strCallbackError
470 )) {
471 __DCL_TRACE1(L"HttpFormData::onFileEnd: %s\n", strCallbackError.data());
472 }
473
474 bNextPart = false;
475 }
476 else {
477 // 정상 데이터
478 if (_begin < _end) {
479 if (!_mapFormFile.onFileData(
480 _begin,
481 _end - _begin,
482 pCallbackData,
483 strCallbackError
484 )
485 ) {
487 HttpFormDataDecoderException::eFormDataCallbackError,
488 strCallbackError
489 );
490 }
491 }
492
493 if (!_mapFormFile.onFileEnd(
494 header,
495 pCallbackData,
496 true,
497 strCallbackError
498 )
499 ) {
501 HttpFormDataDecoderException::eFormDataCallbackError,
502 strCallbackError
503 );
504 }
505
506 if (ds == dsBeforeCloseBoundary)
507 bNextPart = false;
508 }
509 }
510 }
511}
512
513#undef CR
514#undef LF
515#define CR '\r'
516#define LF '\n'
517
518// CRLF을 찾으면 CR의 포인터를, 없으면 NULL을 반환한다.
519inline char* __find_CRLF(
520 char* _begin, char* _end
521 )
522{
523 _end--;
524 while (_begin < _end) {
525 if (*_begin == CR && *(_begin + 1) == LF) {
526 return _begin;
527 }
528 _begin++;
529 }
530 return NULL;
531}
532
533inline char* __find_CHAR(
534 char* _begin, char* _end, char _ch
535 )
536{
537 while (_begin < _end) {
538 if (*_begin == _ch) {
539 return _begin;
540 }
541 _begin++;
542 }
543 return NULL;
544}
545
546HttpFormDataDecoder::DataState
547HttpFormDataDecoder::getDataBlock(
548 const ByteString& _boundary,
549 char*& _begin,
550 char*& _end
551 )
552{
553 __DCL_ASSERT(__buffer != NULL);
554 __DCL_ASSERT(__begin <= __end);
555
556 // 시작 시점에서 버퍼는 적어도
557 // boundary.length() + 2 (close boundary size) 보다 작으면
558 // 데이터가 유효하지 않다.
559 if (!((__begin + _boundary.length() + 2) <= __end)) {
560 return dsNeedMoreData;
561 }
562
563 // CRLF를 확인한 후 CRLF의 이후가 boundary이면
564 // CRLF까지를 _end로
565 _end = _begin = __begin;
566 char* atCR = NULL;
567 while((atCR = __find_CRLF(_end, __end)) != NULL) {
568 // CRLF를 찾았다.
569 // CRLF 다음이 boundary이면 atCR까지이고,
570 // 그렇지 않으면 다음 CRLF를 찾는다.
571 _end = atCR;
572 char* afterCRLF = atCR + 2;
573 __DCL_ASSERT(afterCRLF <= __end);
574 if ((afterCRLF + _boundary.length()) <= __end) {
575 if (!memcmp(_boundary.data(), afterCRLF, _boundary.length())) {
576 DataState dsReturn = dsBeforeNextBoundary;
577 afterCRLF += _boundary.length();
578 if (afterCRLF + 2 <= __end
579 && !memcmp(afterCRLF, "--", 2)) {
580 // close boundary
581 dsReturn = dsBeforeCloseBoundary;
582 }
583
584 // boundary 이후에 CRLF가 있다. skip한다.
585 char* p = __find_CRLF(afterCRLF, __end);
586 if (p) {
587 afterCRLF = p + 2;
588 }
589
590 __DCL_ASSERT(afterCRLF <= __end);
591 __begin = afterCRLF;
592 return dsReturn;
593 }
594 _end = afterCRLF;
595 // 다음 CRLF를 찾는다.
596 }
597 else {
598 // 버퍼의 데이터가 작다. CRLF 찾는것을 종료한다.
599 break;
600 }
601 }
602
603 __DCL_ASSERT(__begin <= _end);
604 if (__begin == _end) {
605 // 한번도 CRLF를 못 찾았다.
606 _end = __end - 1;
607 if (*_end != CR)
608 _end++;
609 }
610
611 __begin = _end;
612 return dsNeedMoreData;
613}
614
615bool HttpFormDataDecoder::getLine(
616 char*& _begin, char*& _end
617 )
618{
619 __DCL_ASSERT(__buffer != NULL);
620 char* atCR = __find_CRLF(__begin, __end);
621 if (!atCR) {
622 return false;
623 }
624
625 _begin = __begin;
626 _end = __begin = atCR;
627
628 // __begin은 CRLF의 다음으로
629 __begin += 2;
630
631 while (_begin < _end) {
632 if (!isspace(*_begin)) {
633 break;
634 }
635 _begin++;
636 }
637
638 return true;
639}
640
641bool HttpFormDataDecoder::getFirstBoundary(
642 const ByteString& _boundary
643 )
644{
645 char* _begin;
646 char* _end;
647 while(getLine(_begin, _end)) {
648 if (((_begin + _boundary.length()) <= _end)
649 && (!memcmp(_boundary.data(), _begin, _boundary.length()))) {
650 // check end boundary
651 _begin += _boundary.length();
652 if (!ByteString::compare(_begin, "--", 2)) {
653 // data error
654 return false;
655 }
656 return true;
657 }
658 }
659 // data error
660 return false;
661}
662
663#define EQUAL_STR(str, p) (!(str).compareNoCase((p), str.length()))
664bool HttpFormDataDecoder::getPartHeader(
665 HttpFormData::PartHeader& header
667{
668 for( ; ; ) {
669 char* _begin;
670 char* _end;
671 if (!getLine(_begin, _end)) {
672 if (!readInput())
673 return false;
674 if (!getLine(_begin, _end))
675 return false;
676 }
677
678 if (!(_begin < _end)) {
679 // 헤더를 모두 읽었다
680 break;
681 }
682
683 char* _value = __find_CHAR(_begin, _end, ':');
684 if (!_value) {
685 // invalid line
686 continue;
687 }
688 while(isspace((byte_t)*(++_value)));
689
690 if (EQUAL_STR(__contentDisposition, _begin)) {
691 _begin = _value;
692 while(_begin < _end) {
693 char* _next = __find_CHAR(_begin, _end, ';');
694 if (!_next) {
695 _next = _end;
696 }
697
698 _value = __find_CHAR(_begin, _next, '=');
699 if (_value) {
700 while(isspace((byte_t)*(++_value)));
701
702 if (EQUAL_STR(__name, _begin)) {
703 header.name = UTF8Decoder::decode(_value, _next - _value).trim(L"\"");
704 }
705 else if (EQUAL_STR(__filename, _begin)) {
706 header.filename = UTF8Decoder::decode(_value, _next - _value).trim(L"\"");
707 // IE는 절대경로를 포함하고 netscape는 basename이다.
708 size_t index = header.filename.lastIndexOf(L'\\');
709 if (index != (size_t)-1) {
710 header.filename = header.filename.mid(index + 1);
711 }
712 }
713 else {
714 String s = String::format(L"unknown property [%ls]",
715 UTF8Decoder::decode(_begin, _end - _begin).data());
716 appendWarning(s);
717 __DCL_TRACE1_N(L"%ls\n", s.data());
718 }
719 }
720 else {
721 header.type = UTF8Decoder::decode(_begin, _next - _begin);
722 }
723
724 if (_next < _end) {
725 while (isspace((byte_t) * (++_next)));
726 }
727 _begin = _next;
728 }
729 }
730 else if (EQUAL_STR(__contentType, _begin)) {
731 header.contentType = UTF8Decoder::decode(_value, _end - _value);
732 }
733 else {
734 String s = String::format(L"Invalid header [%ls]",
735 UTF8Decoder::decode(_begin, _end - _begin).data());
736 appendWarning(s);
737 __DCL_TRACE1_N(L"%ls\n", s.data());
738 }
739 }
740
741 return true;
742}
743
744bool HttpFormDataDecoder::readInput()
746{
747 if (__remainder) {
748 try {
749 if (!__buffer) {
750 __buffer = (char*)malloc(__bufferSize + 1);
751 __DCL_ASSERT(__buffer != NULL);
752 *(__buffer + __bufferSize) = '\0';
753
754 __begin = __buffer;
755 __end = __buffer;
756 }
757
758 size_t n = __end - __begin;
759 if (n) {
760 memmove(__buffer, __begin, n);
761 __begin = __buffer;
762 __end = __buffer + n;
763 }
764 else {
765 // 캐시된 데이터가 없다. 전체를 다시 읽어야 한다.
766 __begin = __buffer;
767 __end = __buffer;
768 }
769
770 size_t nCanRead = __bufferSize - n;
771 if (__remainder < nCanRead)
772 nCanRead = __remainder;
773
774 size_t nRead = __input->read(__end, nCanRead);
775 __end += nRead;
776 __DCL_TRACE2_N(L"CanRead: %d, Read: %d\n", nCanRead, nRead);
777 __remainder -= nRead;
778
779 return true;
780 }
781 catch(IOException* eCause) {
782 throw new HttpFormDataDecoderException(
783 HttpFormDataDecoderException::ePostReadError,
784 eCause
785 );
786 }
787 }
788 return false;
789}
790
791void HttpFormDataDecoder::appendWarning(const String& _warning)
792{
793
794 if (!__warnings.isEmpty())
795 __warnings += L'\n';
796
797 __warnings += _warning;
798}
799
800// static members
801ByteString HttpFormDataDecoder::getBoundary(
802 const char* _contentType
803 )
804{
805 __DCL_ASSERT(_contentType != NULL && *_contentType != '\0');
806
807 ByteStringBuilder sb;
808
809 const char* p = strstr(_contentType, "boundary");
810 if (p) {
811 p += 8; // strlen("boundary");
812 p = strchr(p, '=');
813 if (p) {
814 while(isspace((byte_t)*(++p)))
815 ;
816 sb = p;
817 sb.trim();
818 }
819 }
820
821 return sb;
822}
823
824bool HttpFormDataDecoder::isValidType(const char* _contentType)
825{
826 __DCL_ASSERT(_contentType != NULL
827 && *_contentType != '\0');
828
829 while(isspace((byte_t)*_contentType))
830 _contentType++;
831
832 return ByteString::compareNoCase(
833 _contentType,
834 "multipart/form-data",
835 19
836 ) == 0;
837}
838
840
841BufferedHttpFormData::FileInfo::FileInfo()
842{
843}
844
845#undef __V
846#define __V() ((PointerArray*)__handle)
847BufferedHttpFormData::FileInfo&
848BufferedHttpFormData::FileInfoArray::operator[] (size_t _index)
849{
850 __DCL_ASSERT(_index < __V()->size());
851
852 return *((FileInfo*)((*__V())[_index]));
853}
854
855size_t BufferedHttpFormData::FileInfoArray::size() const
856{
857 __DCL_ASSERT(__handle != NULL);
858
859 return __V()->size();
860}
861
862bool BufferedHttpFormData::FileInfoArray::isEmpty() const
863{
864 __DCL_ASSERT(__handle != NULL);
865
866 return __V()->isEmpty();
867}
868
869BufferedHttpFormData::FileInfoArray::FileInfoArray(const String& _name)
870{
871 __handle = new PointerArray();
872 __name = _name;
873
874 __DCL_ASSERT(__handle != NULL);
875}
876
877BufferedHttpFormData::FileInfoArray::FileInfoArray(const FileInfo& src)
878{
879 // 결코 불려져서는 안됨
880 __DCL_ASSERT(false);
881}
882
883BufferedHttpFormData::FileInfoArray::~FileInfoArray()
884{
885 __DCL_ASSERT(__handle != NULL);
886 PointerArray* p = __V();
887 PointerArray& v = *p;
888 for(size_t i = 0; i < v.size(); i++)
889 delete (FileInfo*)v[i];
890 v.clear();
891 delete p;
892}
893
894void BufferedHttpFormData::FileInfoArray::add(FileInfo* pNewItem)
895{
896 __DCL_ASSERT(pNewItem != NULL);
897 __V()->add(pNewItem);
898}
899
901{
902 __handle = new PointerArray();
903 __DCL_ASSERT(__handle != NULL);
904}
905
907{
908 __DCL_ASSERT(__handle != NULL);
909 PointerArray* p = __V();
910 PointerArray& v = *p;
911 for(size_t i = 0; i < v.size(); i++)
912 delete (FileInfoArray*)v[i];
913 v.clear();
914 delete p;
915}
916
918{
919 __DCL_ASSERT(__handle != NULL);
920 return __V()->size();
921}
922
924{
925 __DCL_ASSERT(__handle != NULL);
926
927 return __V()->isEmpty();
928}
929
930BufferedHttpFormData::FileInfoArray&
932{
933 __DCL_ASSERT(_index < __V()->size());
934 return *((FileInfoArray*)((*__V())[_index]));
935}
936
937BufferedHttpFormData::FileInfoArray&
938BufferedHttpFormData::byName(const wchar_t* _name)
940{
941 __DCL_ASSERT(_name != NULL && *_name != '\0');
942
943 FileInfoArray* pV = NULL;
944 PointerArray& v = *(PointerArray*)__handle;
945 for(size_t i = 0; i < v.size(); i++)
946 {
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(pOut != NULL);
977
978 *ppCallbackData = pOut;
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* pOut = (BytesOutputStream*)pCallbackData;
991 __DCL_ASSERT(pOut != NULL);
992
993 try {
994 pOut->write(pData, nSize);
995 }
996 catch(IOException* e) {
997 delete pOut;
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* pOut = (BytesOutputStream*)pCallbackData;
1015 __DCL_ASSERT(pOut != NULL);
1016
1017 if (bDataSuccess) {
1018 FileInfo* pInfo = new FileInfo;
1019
1020 pInfo->filename = header.filename;
1021 pInfo->contentType = header.contentType;
1022 pInfo->fileData = pOut->toByteString();
1023
1024 delete pOut;
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
1186
1188 const PartHeader& header,
1189 void** ppCallbackData,
1190 String& strCallbackError // return false 이면
1191 )
1192{
1193 String filename;
1194 FileOutputStream* pOut = NULL;
1195 try {
1196 File* pFile = File::openTempFile(
1197 __tempDir,
1198 L"dclformdata"
1199 );
1200 pOut = new FileOutputStream(pFile);
1201 filename = pFile->path();
1202 }
1203 catch(IOException* e) {
1204 if (!filename.isEmpty()) {
1205 try {
1206 Files::unlink(filename);
1207 }
1208 catch (IOException* e) {
1209 __DCL_TRACE1(L"%ls\n", e->toString().data());
1210 e->destroy();
1211 }
1212 }
1213 strCallbackError = e->toString();
1214 e->destroy();
1215 return false;
1216 }
1217
1219 __DCL_ASSERT(pCB != NULL);
1220 pCB->tempFilename = filename;
1221 pCB->output = pOut;
1222 pCB->dataSize = 0;
1223
1224 *ppCallbackData = pCB;
1225
1226 return true;
1227}
1228
1230 const void* pData,
1231 size_t nSize,
1232 void* pCallbackData,
1233 String& strCallbackError // return false 이면
1234 )
1235{
1236 STORED_CALLBACK_DATA* pCB = (STORED_CALLBACK_DATA*)pCallbackData;
1237 __DCL_ASSERT(pCB != NULL);
1238
1239 try {
1240 pCB->output->write(pData, nSize);
1241 pCB->dataSize += nSize;
1242 }
1243 catch(IOException* e) {
1244 try {
1245 delete pCB->output;
1247 }
1248 catch(IOException* e) {
1249 __DCL_TRACE1(L"%ls\n", e->toString().data());
1250 e->destroy();
1251 }
1252
1253 delete pCB;
1254
1255 strCallbackError = e->toString();
1256 e->destroy();
1257 return false;
1258 }
1259 return true;
1260}
1261
1263 const PartHeader& header,
1264 void* pCallbackData,
1265 bool bDataSuccess,
1266 String& strCallbackError // return false 이면
1267 )
1268{
1269 STORED_CALLBACK_DATA* pCB = (STORED_CALLBACK_DATA*)pCallbackData;
1270 __DCL_ASSERT(pCB != NULL);
1271 try {
1272 delete pCB->output;
1273
1275 L"fileSize: %zd, dataSize: %zd\n",
1277 pCB->dataSize
1278 );
1279 }
1280 catch(IOException* e) {
1281 try {
1283 }
1284 catch(IOException* e) {
1285 __DCL_TRACE1(L"%ls\n", e->toString().data());
1286 e->destroy();
1287 }
1288
1289 strCallbackError = e->toString();
1290 e->destroy();
1291 delete pCB;
1292
1293 return false;
1294 }
1295
1296
1297 if (bDataSuccess) {
1298 FileInfo* pInfo = new FileInfo;
1299
1300 __DCL_ASSERT(pInfo != NULL);
1301
1302 pInfo->filename = header.filename;
1303 pInfo->contentType = header.contentType;
1304 pInfo->fileSize = pCB->dataSize;
1305 pInfo->tempFilename = pCB->tempFilename;
1306
1307 insert(header.name, pInfo);
1308 }
1309
1310 delete pCB;
1311
1312 return true;
1313}
1314
1315__DCL_END_NAMESPACE
#define __THIS_FILE__
Definition _trace.h:14
#define NULL
Definition Config.h:340
wchar_t char_t
Definition Config.h:275
unsigned char byte_t
Definition Config.h:274
#define __DCL_THROWS1(e)
Definition Config.h:167
char * __find_CHAR(char *_begin, char *_end, char _ch)
struct _STORED_CALLBACK_DATA STORED_CALLBACK_DATA
#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:375
#define __DCL_TRACE1(fmt, arg1)
Definition Object.h:376
#define __DCL_ASSERT(expr)
Definition Object.h:371
#define IMPLEMENT_CLASSINFO(class_name, base_class_name)
Definition Object.h:228
#define __T(str)
Definition Object.h:44
void CharsetConvertException *size_t n
Definition SQLField.cpp:253
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:38
static File * openTempFile(const String &_dirname, const String &_prefix, unsigned int _mode=0666) __DCL_THROWS1(IOException *)
Definition File.cpp:721
const String & path() const
Definition File.h:247
static bool exists(const String &_path)
Definition Files.cpp:109
static uint64_t size(const String &_path) __DCL_THROWS1(IOException *)
Definition Files.cpp:161
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
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:83
FileOutputStream * output