2006-10-23 18:25:09 +02:00
|
|
|
//
|
|
|
|
// HTMLForm.cpp
|
|
|
|
//
|
2008-01-28 18:34:07 +01:00
|
|
|
// $Id: //poco/svn/Net/src/HTMLForm.cpp#3 $
|
2006-10-23 18:25:09 +02:00
|
|
|
//
|
|
|
|
// Library: Net
|
|
|
|
// Package: HTML
|
|
|
|
// Module: HTMLForm
|
|
|
|
//
|
|
|
|
// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
|
|
|
|
// and Contributors.
|
|
|
|
//
|
|
|
|
// Permission is hereby granted, free of charge, to any person or organization
|
|
|
|
// obtaining a copy of the software and accompanying documentation covered by
|
|
|
|
// this license (the "Software") to use, reproduce, display, distribute,
|
|
|
|
// execute, and transmit the Software, and to prepare derivative works of the
|
|
|
|
// Software, and to permit third-parties to whom the Software is furnished to
|
|
|
|
// do so, all subject to the following:
|
|
|
|
//
|
|
|
|
// The copyright notices in the Software and this entire statement, including
|
|
|
|
// the above license grant, this restriction and the following disclaimer,
|
|
|
|
// must be included in all copies of the Software, in whole or in part, and
|
|
|
|
// all derivative works of the Software, unless such copies or derivative
|
|
|
|
// works are solely in the form of machine-executable object code generated by
|
|
|
|
// a source language processor.
|
|
|
|
//
|
|
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
|
|
|
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
|
|
|
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
|
|
|
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
|
|
// DEALINGS IN THE SOFTWARE.
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
|
|
#include "Poco/Net/HTMLForm.h"
|
|
|
|
#include "Poco/Net/HTTPRequest.h"
|
|
|
|
#include "Poco/Net/PartSource.h"
|
|
|
|
#include "Poco/Net/PartHandler.h"
|
|
|
|
#include "Poco/Net/MultipartWriter.h"
|
|
|
|
#include "Poco/Net/MultipartReader.h"
|
|
|
|
#include "Poco/Net/NullPartHandler.h"
|
|
|
|
#include "Poco/NullStream.h"
|
2007-02-23 15:41:53 +01:00
|
|
|
#include "Poco/CountingStream.h"
|
2006-10-23 18:25:09 +02:00
|
|
|
#include "Poco/StreamCopier.h"
|
|
|
|
#include "Poco/Exception.h"
|
|
|
|
#include "Poco/URI.h"
|
|
|
|
#include "Poco/String.h"
|
|
|
|
#include <sstream>
|
|
|
|
|
|
|
|
|
|
|
|
using Poco::NullInputStream;
|
|
|
|
using Poco::StreamCopier;
|
|
|
|
using Poco::SyntaxException;
|
|
|
|
using Poco::URI;
|
|
|
|
using Poco::icompare;
|
|
|
|
|
|
|
|
|
|
|
|
namespace Poco {
|
|
|
|
namespace Net {
|
|
|
|
|
|
|
|
|
|
|
|
const std::string HTMLForm::ENCODING_URL = "application/x-www-form-urlencoded";
|
|
|
|
const std::string HTMLForm::ENCODING_MULTIPART = "multipart/form-data";
|
|
|
|
|
|
|
|
|
|
|
|
HTMLForm::HTMLForm():
|
|
|
|
_encoding(ENCODING_URL)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
HTMLForm::HTMLForm(const std::string& encoding):
|
|
|
|
_encoding(encoding)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
HTMLForm::HTMLForm(const HTTPRequest& request, std::istream& requestBody, PartHandler& handler)
|
|
|
|
{
|
|
|
|
load(request, requestBody, handler);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
HTMLForm::HTMLForm(const HTTPRequest& request, std::istream& requestBody)
|
|
|
|
{
|
|
|
|
load(request, requestBody);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
HTMLForm::HTMLForm(const HTTPRequest& request)
|
|
|
|
{
|
|
|
|
load(request);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
HTMLForm::~HTMLForm()
|
|
|
|
{
|
|
|
|
for (PartVec::iterator it = _parts.begin(); it != _parts.end(); ++it)
|
|
|
|
{
|
|
|
|
delete it->pSource;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void HTMLForm::setEncoding(const std::string& encoding)
|
|
|
|
{
|
|
|
|
_encoding = encoding;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void HTMLForm::addPart(const std::string& name, PartSource* pSource)
|
|
|
|
{
|
|
|
|
poco_check_ptr (pSource);
|
|
|
|
|
|
|
|
Part part;
|
|
|
|
part.name = name;
|
|
|
|
part.pSource = pSource;
|
|
|
|
_parts.push_back(part);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void HTMLForm::load(const HTTPRequest& request, std::istream& requestBody, PartHandler& handler)
|
|
|
|
{
|
2008-09-16 19:26:28 +02:00
|
|
|
clear();
|
2011-09-14 20:20:11 +02:00
|
|
|
if (request.getMethod() == HTTPRequest::HTTP_POST || request.getMethod() == HTTPRequest::HTTP_PUT)
|
2006-10-23 18:25:09 +02:00
|
|
|
{
|
|
|
|
std::string mediaType;
|
|
|
|
NameValueCollection params;
|
|
|
|
MessageHeader::splitParameters(request.getContentType(), mediaType, params);
|
|
|
|
_encoding = mediaType;
|
|
|
|
if (_encoding == ENCODING_MULTIPART)
|
|
|
|
{
|
|
|
|
_boundary = params["boundary"];
|
|
|
|
readMultipart(requestBody, handler);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
readUrl(requestBody);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
URI uri(request.getURI());
|
|
|
|
std::istringstream istr(uri.getRawQuery());
|
|
|
|
readUrl(istr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void HTMLForm::load(const HTTPRequest& request, std::istream& requestBody)
|
|
|
|
{
|
|
|
|
NullPartHandler nah;
|
|
|
|
load(request, requestBody, nah);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void HTMLForm::load(const HTTPRequest& request)
|
|
|
|
{
|
|
|
|
NullPartHandler nah;
|
|
|
|
NullInputStream nis;
|
|
|
|
load(request, nis, nah);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void HTMLForm::read(std::istream& istr, PartHandler& handler)
|
|
|
|
{
|
|
|
|
if (_encoding == ENCODING_URL)
|
|
|
|
readUrl(istr);
|
|
|
|
else
|
|
|
|
readMultipart(istr, handler);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void HTMLForm::prepareSubmit(HTTPRequest& request)
|
|
|
|
{
|
2011-09-14 20:20:11 +02:00
|
|
|
if (request.getMethod() == HTTPRequest::HTTP_POST || request.getMethod() == HTTPRequest::HTTP_PUT)
|
2006-10-23 18:25:09 +02:00
|
|
|
{
|
|
|
|
if (_encoding == ENCODING_URL)
|
|
|
|
{
|
|
|
|
request.setContentType(_encoding);
|
2007-02-23 15:41:53 +01:00
|
|
|
request.setChunkedTransferEncoding(false);
|
|
|
|
Poco::CountingOutputStream ostr;
|
|
|
|
writeUrl(ostr);
|
|
|
|
request.setContentLength(ostr.chars());
|
2006-10-23 18:25:09 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
_boundary = MultipartWriter::createBoundary();
|
|
|
|
std::string ct(_encoding);
|
|
|
|
ct.append("; boundary=\"");
|
|
|
|
ct.append(_boundary);
|
|
|
|
ct.append("\"");
|
|
|
|
request.setContentType(ct);
|
|
|
|
}
|
|
|
|
if (request.getVersion() == HTTPMessage::HTTP_1_0)
|
|
|
|
{
|
|
|
|
request.setKeepAlive(false);
|
|
|
|
request.setChunkedTransferEncoding(false);
|
|
|
|
}
|
2007-02-23 15:41:53 +01:00
|
|
|
else if (_encoding != ENCODING_URL)
|
2006-10-23 18:25:09 +02:00
|
|
|
{
|
|
|
|
request.setChunkedTransferEncoding(true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
std::string uri = request.getURI();
|
|
|
|
std::ostringstream ostr;
|
2007-02-23 15:41:53 +01:00
|
|
|
writeUrl(ostr);
|
2006-10-23 18:25:09 +02:00
|
|
|
uri.append("?");
|
|
|
|
uri.append(ostr.str());
|
|
|
|
request.setURI(uri);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void HTMLForm::write(std::ostream& ostr, const std::string& boundary)
|
|
|
|
{
|
|
|
|
if (_encoding == ENCODING_URL)
|
|
|
|
{
|
|
|
|
writeUrl(ostr);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
_boundary = boundary;
|
|
|
|
writeMultipart(ostr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void HTMLForm::write(std::ostream& ostr)
|
|
|
|
{
|
|
|
|
if (_encoding == ENCODING_URL)
|
|
|
|
writeUrl(ostr);
|
|
|
|
else
|
|
|
|
writeMultipart(ostr);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void HTMLForm::readUrl(std::istream& istr)
|
|
|
|
{
|
|
|
|
static const int eof = std::char_traits<char>::eof();
|
|
|
|
|
|
|
|
int ch = istr.get();
|
|
|
|
while (ch != eof)
|
|
|
|
{
|
|
|
|
std::string name;
|
|
|
|
std::string value;
|
|
|
|
while (ch != eof && ch != '=' && ch != '&')
|
|
|
|
{
|
|
|
|
if (ch == '+') ch = ' ';
|
|
|
|
name += (char) ch;
|
|
|
|
ch = istr.get();
|
|
|
|
}
|
|
|
|
if (ch == '=')
|
|
|
|
{
|
|
|
|
ch = istr.get();
|
|
|
|
while (ch != eof && ch != '&')
|
|
|
|
{
|
|
|
|
if (ch == '+') ch = ' ';
|
|
|
|
value += (char) ch;
|
|
|
|
ch = istr.get();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
std::string decodedName;
|
|
|
|
std::string decodedValue;
|
|
|
|
URI::decode(name, decodedName);
|
|
|
|
URI::decode(value, decodedValue);
|
|
|
|
add(decodedName, decodedValue);
|
|
|
|
if (ch == '&') ch = istr.get();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void HTMLForm::readMultipart(std::istream& istr, PartHandler& handler)
|
|
|
|
{
|
|
|
|
static const int eof = std::char_traits<char>::eof();
|
|
|
|
|
|
|
|
MultipartReader reader(istr, _boundary);
|
|
|
|
while (reader.hasNextPart())
|
|
|
|
{
|
|
|
|
MessageHeader header;
|
|
|
|
reader.nextPart(header);
|
|
|
|
std::string disp;
|
|
|
|
NameValueCollection params;
|
|
|
|
if (header.has("Content-Disposition"))
|
|
|
|
{
|
|
|
|
std::string cd = header.get("Content-Disposition");
|
|
|
|
MessageHeader::splitParameters(cd, disp, params);
|
|
|
|
}
|
|
|
|
if (params.has("filename"))
|
|
|
|
{
|
|
|
|
handler.handlePart(header, reader.stream());
|
|
|
|
// Ensure that the complete part has been read.
|
|
|
|
while (reader.stream().good()) reader.stream().get();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
std::string name = params["name"];
|
|
|
|
std::string value;
|
|
|
|
std::istream& istr = reader.stream();
|
|
|
|
int ch = istr.get();
|
|
|
|
while (ch != eof)
|
|
|
|
{
|
|
|
|
value += (char) ch;
|
|
|
|
ch = istr.get();
|
|
|
|
}
|
|
|
|
add(name, value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void HTMLForm::writeUrl(std::ostream& ostr)
|
|
|
|
{
|
|
|
|
for (NameValueCollection::ConstIterator it = begin(); it != end(); ++it)
|
|
|
|
{
|
|
|
|
if (it != begin()) ostr << "&";
|
|
|
|
std::string name;
|
2011-09-14 20:20:11 +02:00
|
|
|
URI::encode(it->first, "=&+;", name);
|
2006-10-23 18:25:09 +02:00
|
|
|
std::string value;
|
2011-09-14 20:20:11 +02:00
|
|
|
URI::encode(it->second, "=&+;", value);
|
2006-10-23 18:25:09 +02:00
|
|
|
ostr << name << "=" << value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void HTMLForm::writeMultipart(std::ostream& ostr)
|
|
|
|
{
|
|
|
|
MultipartWriter writer(ostr, _boundary);
|
|
|
|
for (NameValueCollection::ConstIterator it = begin(); it != end(); ++it)
|
|
|
|
{
|
|
|
|
MessageHeader header;
|
|
|
|
std::string disp("form-data; name=\"");
|
|
|
|
disp.append(it->first);
|
|
|
|
disp.append("\"");
|
|
|
|
header.set("Content-Disposition", disp);
|
|
|
|
writer.nextPart(header);
|
|
|
|
ostr << it->second;
|
|
|
|
}
|
|
|
|
for (PartVec::iterator ita = _parts.begin(); ita != _parts.end(); ++ita)
|
|
|
|
{
|
2011-09-14 20:20:11 +02:00
|
|
|
MessageHeader header(ita->pSource->headers());
|
|
|
|
std::string disp("form-data; name=\"");
|
2006-10-23 18:25:09 +02:00
|
|
|
disp.append(ita->name);
|
|
|
|
disp.append("\"");
|
|
|
|
std::string filename = ita->pSource->filename();
|
|
|
|
if (!filename.empty())
|
|
|
|
{
|
|
|
|
disp.append("; filename=\"");
|
|
|
|
disp.append(filename);
|
|
|
|
disp.append("\"");
|
|
|
|
}
|
|
|
|
header.set("Content-Disposition", disp);
|
|
|
|
header.set("Content-Type", ita->pSource->mediaType());
|
|
|
|
writer.nextPart(header);
|
|
|
|
StreamCopier::copyStream(ita->pSource->stream(), ostr);
|
|
|
|
}
|
|
|
|
writer.close();
|
|
|
|
_boundary = writer.boundary();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
} } // namespace Poco::Net
|