Skip to content

Commit 731fb29

Browse files
committed
Merge pull request pocoproject#344 from RangelReale/htmlformcontentlength
HTMLForm Content-Length calculation
2 parents 89b7228 + 0d2a839 commit 731fb29

12 files changed

Lines changed: 164 additions & 5 deletions

File tree

‎Foundation/include/Poco/CountingStream.h‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,15 @@ class Foundation_API CountingStreamBuf: public UnbufferedStreamBuf
6969
int getCurrentLineNumber() const;
7070
/// Returns the current line number (same as lines()).
7171

72+
void addChars(int chars);
73+
/// Add to the total number of characters.
74+
75+
void addLines(int lines);
76+
/// Add to the total number of lines.
77+
78+
void addPos(int pos);
79+
/// Add to the number of characters on the current line.
80+
7281
protected:
7382
int readFromDevice();
7483
int writeToDevice(char c);
@@ -124,6 +133,15 @@ class Foundation_API CountingIOS: public virtual std::ios
124133
int getCurrentLineNumber() const;
125134
/// Returns the current line number (same as lines()).
126135

136+
void addChars(int chars);
137+
/// Add to the total number of characters.
138+
139+
void addLines(int lines);
140+
/// Add to the total number of lines.
141+
142+
void addPos(int pos);
143+
/// Add to the number of characters on the current line.
144+
127145
CountingStreamBuf* rdbuf();
128146
/// Returns a pointer to the underlying streambuf.
129147

‎Foundation/src/CountingStream.cpp‎

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,24 @@ void CountingStreamBuf::setCurrentLineNumber(int line)
9696
}
9797

9898

99+
void CountingStreamBuf::addChars(int chars)
100+
{
101+
_chars += chars;
102+
}
103+
104+
105+
void CountingStreamBuf::addLines(int lines)
106+
{
107+
_lines += lines;
108+
}
109+
110+
111+
void CountingStreamBuf::addPos(int pos)
112+
{
113+
_pos += pos;
114+
}
115+
116+
99117
CountingIOS::CountingIOS()
100118
{
101119
poco_ios_init(&_buf);
@@ -131,6 +149,24 @@ void CountingIOS::setCurrentLineNumber(int line)
131149
}
132150

133151

152+
void CountingIOS::addChars(int chars)
153+
{
154+
_buf.addChars(chars);
155+
}
156+
157+
158+
void CountingIOS::addLines(int lines)
159+
{
160+
_buf.addLines(lines);
161+
}
162+
163+
164+
void CountingIOS::addPos(int pos)
165+
{
166+
_buf.addPos(pos);
167+
}
168+
169+
134170
CountingStreamBuf* CountingIOS::rdbuf()
135171
{
136172
return &_buf;

‎Foundation/testsuite/src/CountingStreamTest.cpp‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,16 @@ void CountingStreamTest::testInput()
5454
assert (ci3.lines() == 2);
5555
assert (ci3.chars() == 8);
5656
assert (ci3.pos() == 0);
57+
58+
std::istringstream istr4("foo");
59+
CountingInputStream ci4(istr4);
60+
while (ci4.good()) ci4.get(c);
61+
ci4.addChars(10);
62+
ci4.addLines(2);
63+
ci4.addPos(3);
64+
assert (ci4.lines() == 1 + 2);
65+
assert (ci4.chars() == 3 + 10);
66+
assert (ci4.pos() == 3 + 3);
5767
}
5868

5969

@@ -80,6 +90,16 @@ void CountingStreamTest::testOutput()
8090
assert (co3.lines() == 2);
8191
assert (co3.chars() == 8);
8292
assert (co3.pos() == 0);
93+
94+
std::ostringstream ostr4;
95+
CountingOutputStream co4(ostr4);
96+
co4 << "foo";
97+
co4.addChars(10);
98+
co4.addLines(2);
99+
co4.addPos(3);
100+
assert (co4.lines() == 1 + 2);
101+
assert (co4.chars() == 3 + 10);
102+
assert (co4.pos() == 3 + 3);
83103
}
84104

85105

‎Net/include/Poco/Net/FilePartSource.h‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,11 @@ class Net_API FilePartSource: public PartSource
6363
const std::string& filename() const;
6464
/// Returns the filename portion of the path.
6565

66+
std::streamsize getContentLength() const;
67+
/// Returns the file size.
68+
6669
private:
70+
std::string _path;
6771
std::string _filename;
6872
Poco::FileInputStream _istr;
6973
};

‎Net/include/Poco/Net/HTMLForm.h‎

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,14 @@ class Net_API HTMLForm: public NameValueCollection
153153
/// Otherwise, if the request's HTTP version is HTTP/1.1:
154154
/// - the request's persistent connection state is left unchanged
155155
/// - the content transfer encoding is set to chunked
156-
156+
157+
158+
std::streamsize calculateContentLength();
159+
/// Calculate the content length for the form.
160+
/// May be UNKNOWN_CONTENT_LENGTH if not possible
161+
/// to calculate
162+
163+
157164
void write(std::ostream& ostr, const std::string& boundary);
158165
/// Writes the form data to the given output stream,
159166
/// using the specified encoding.
@@ -183,6 +190,7 @@ class Net_API HTMLForm: public NameValueCollection
183190
static const std::string ENCODING_URL; /// "application/x-www-form-urlencoded"
184191
static const std::string ENCODING_MULTIPART; /// "multipart/form-data"
185192

193+
static const int UNKNOWN_CONTENT_LENGTH;
186194
protected:
187195
void readUrl(std::istream& istr);
188196
void readMultipart(std::istream& istr, PartHandler& handler);

‎Net/include/Poco/Net/PartSource.h‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,15 @@ class Net_API PartSource
5757
/// Returns a MessageHeader containing additional header
5858
/// fields for the part.
5959

60+
virtual std::streamsize getContentLength() const;
61+
/// Returns the content length for this part
62+
/// which may be UNKNOWN_CONTENT_LENGTH if
63+
/// not available.
64+
6065
virtual ~PartSource();
6166
/// Destroys the PartSource.
6267

68+
static const int UNKNOWN_CONTENT_LENGTH;
6369
protected:
6470
PartSource();
6571
/// Creates the PartSource, using

‎Net/include/Poco/Net/StringPartSource.h‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ class Net_API StringPartSource: public PartSource
5555
const std::string& filename() const;
5656
/// Returns the filename portion of the path.
5757

58+
std::streamsize getContentLength() const;
59+
/// Returns the string size.
60+
5861
private:
5962
std::istringstream _istr;
6063
std::string _filename;

‎Net/src/FilePartSource.cpp‎

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
#include "Poco/Net/FilePartSource.h"
1818
#include "Poco/Path.h"
19+
#include "Poco/File.h"
1920
#include "Poco/Exception.h"
2021

2122

@@ -28,7 +29,7 @@ namespace Net {
2829

2930

3031
FilePartSource::FilePartSource(const std::string& path):
31-
_istr(path)
32+
_path(path), _istr(path)
3233
{
3334
Path p(path);
3435
_filename = p.getFileName();
@@ -39,6 +40,7 @@ FilePartSource::FilePartSource(const std::string& path):
3940

4041
FilePartSource::FilePartSource(const std::string& path, const std::string& mediaType):
4142
PartSource(mediaType),
43+
_path(path),
4244
_istr(path)
4345
{
4446
Path p(path);
@@ -50,6 +52,7 @@ FilePartSource::FilePartSource(const std::string& path, const std::string& media
5052

5153
FilePartSource::FilePartSource(const std::string& path, const std::string& filename, const std::string& mediaType):
5254
PartSource(mediaType),
55+
_path(path),
5356
_filename(filename),
5457
_istr(path)
5558
{
@@ -76,4 +79,11 @@ const std::string& FilePartSource::filename() const
7679
}
7780

7881

82+
std::streamsize FilePartSource::getContentLength() const
83+
{
84+
Poco::File p(_path);
85+
return p.getSize();
86+
}
87+
88+
7989
} } // namespace Poco::Net

‎Net/src/HTMLForm.cpp‎

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include "Poco/StreamCopier.h"
2828
#include "Poco/URI.h"
2929
#include "Poco/String.h"
30+
#include "Poco/CountingStream.h"
3031
#include <sstream>
3132

3233

@@ -41,8 +42,21 @@ namespace Poco {
4142
namespace Net {
4243

4344

44-
const std::string HTMLForm::ENCODING_URL = "application/x-www-form-urlencoded";
45-
const std::string HTMLForm::ENCODING_MULTIPART = "multipart/form-data";
45+
const std::string HTMLForm::ENCODING_URL = "application/x-www-form-urlencoded";
46+
const std::string HTMLForm::ENCODING_MULTIPART = "multipart/form-data";
47+
const int HTMLForm::UNKNOWN_CONTENT_LENGTH = -1;
48+
49+
50+
class HTMLFormCountingOutputStream : public CountingOutputStream
51+
{
52+
public:
53+
HTMLFormCountingOutputStream() : _isvalid(true) {}
54+
55+
bool getIsValid() const { return _isvalid; }
56+
void setIsValid(bool v) { _isvalid = v; }
57+
private:
58+
bool _isvalid;
59+
};
4660

4761

4862
HTMLForm::HTMLForm():
@@ -217,6 +231,20 @@ void HTMLForm::prepareSubmit(HTTPRequest& request)
217231
}
218232

219233

234+
std::streamsize HTMLForm::calculateContentLength()
235+
{
236+
if (_boundary.empty())
237+
throw HTMLFormException("Form must be prepared");
238+
239+
HTMLFormCountingOutputStream c;
240+
write(c);
241+
if (c.getIsValid())
242+
return c.chars();
243+
else
244+
return UNKNOWN_CONTENT_LENGTH;
245+
}
246+
247+
220248
void HTMLForm::write(std::ostream& ostr, const std::string& boundary)
221249
{
222250
if (_encoding == ENCODING_URL)
@@ -338,6 +366,8 @@ void HTMLForm::writeUrl(std::ostream& ostr)
338366

339367
void HTMLForm::writeMultipart(std::ostream& ostr)
340368
{
369+
HTMLFormCountingOutputStream *costr(dynamic_cast<HTMLFormCountingOutputStream*>(&ostr));
370+
341371
MultipartWriter writer(ostr, _boundary);
342372
for (NameValueCollection::ConstIterator it = begin(); it != end(); ++it)
343373
{
@@ -365,7 +395,17 @@ void HTMLForm::writeMultipart(std::ostream& ostr)
365395
header.set("Content-Disposition", disp);
366396
header.set("Content-Type", ita->pSource->mediaType());
367397
writer.nextPart(header);
368-
StreamCopier::copyStream(ita->pSource->stream(), ostr);
398+
if (costr)
399+
{
400+
// count only, don't move stream position
401+
std::streamsize partlen = ita->pSource->getContentLength();
402+
if (partlen != PartSource::UNKNOWN_CONTENT_LENGTH)
403+
costr->addChars(partlen);
404+
else
405+
costr->setIsValid(false);
406+
}
407+
else
408+
StreamCopier::copyStream(ita->pSource->stream(), ostr);
369409
}
370410
writer.close();
371411
_boundary = writer.boundary();

‎Net/src/PartSource.cpp‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ namespace Poco {
2121
namespace Net {
2222

2323

24+
const int PartSource::UNKNOWN_CONTENT_LENGTH = -1;
25+
26+
2427
PartSource::PartSource():
2528
_mediaType("application/octet-stream")
2629
{
@@ -49,5 +52,9 @@ const std::string& PartSource::filename() const
4952
return EMPTY;
5053
}
5154

55+
std::streamsize PartSource::getContentLength() const
56+
{
57+
return UNKNOWN_CONTENT_LENGTH;
58+
}
5259

5360
} } // namespace Poco::Net

0 commit comments

Comments
 (0)