Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HttpRequest improvements and move HttpParams into separate module #1498

Merged
merged 5 commits into from
Oct 22, 2018
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 28 additions & 13 deletions Sming/Services/WebHelpers/escape.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,8 @@ char *uri_escape(char *dest, size_t dest_len, const char *src, int src_len)
/* escape these values ~!#$%^&(){}[]=:,;?'"\
* make sure there is room in dest for a '\0' */
for(;src_len>0 && dest_len>1;src++,src_len--) {
if(must_escape(*src)) {
char c = *src;
if(must_escape(c)) {
/* check that there is room for "%XX\0" in dest */
if(dest_len<=3) {
if(ret_is_allocated)
Expand All @@ -113,6 +114,9 @@ char *uri_escape(char *dest, size_t dest_len, const char *src, int src_len)
dest[2] = hexchar(*src & 0x0f);
dest+=3;
dest_len-=3;
} else if (c == ' ') {
*dest++ = '+';
dest_len--;
} else {
*(dest++)=*src;
dest_len--;
Expand Down Expand Up @@ -232,23 +236,34 @@ void html_escape(char *dest, size_t len, const char *s) {

String uri_escape(const char *src, int src_len)
{
char* p = uri_escape(nullptr, 0, src, src_len);
String s(p);
if (p)
free(p);
String s;
if (src && src_len) {
unsigned dst_len = uri_escape_len(src, src_len);
if (s.setLength(dst_len))
uri_escape(s.begin(), s.length() + 1, src, src_len); // +1 for nul terminator
}
return s;
}

int uri_unescape_inplace(String& s)
char* uri_unescape_inplace(char *str)
{
// If string is invalid, ensure result remains invalid
if (!s)
return 0;
if (str) {
auto len = strlen(str);
uri_unescape(str, len + 1, str, len); // +1 for nul terminator
}
return str;
}

char* p = s.begin();
uri_unescape(p, s.length(), p, s.length());
s.setLength(strlen(p));
return s.length();
String& uri_unescape_inplace(String& str)
{
if (str) {
char* p = str.begin();
uri_unescape(p, str.length() + 1, p, str.length()); // +1 for nul terminator
auto len = strlen(p);
assert(len <= str.length());
str.setLength(len);
}
return str;
}


49 changes: 44 additions & 5 deletions Sming/Services/WebHelpers/escape.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,50 @@
#include <user_config.h>
#include "WString.h"

/** @brief Obtain number of characters required to escape the given text
* @param s source text
* @param len Number of characters in source text
* @retval unsigned number of characters for output, NOT including nul terminator
*/
unsigned uri_escape_len(const char *s, size_t len);

static inline unsigned uri_escape_len(const String& str)
{
return uri_escape_len(str.c_str(), str.length());
}

/** @brief Escape text
* @param dest buffer to store result
* @param dest_len available space in dest; requires +1 extra character for nul terminator,
* so at least uri_escape_len() + 1
* @param src source text to escape
* @param src_len number of characters in source
* @retval char* points to start of dest
* @note destination and source MUST be different buffers
*/
char *uri_escape(char *dest, size_t dest_len, const char *src, int src_len);

/** @brief unescape text
* @param dest buffer to store result
* @param dest_len available space in dest; requires +1 extra character for nul terminator
* @param src source text to un-escape
* @param src_len number of characters in source
* @retval char* points to start of dest
* @note destination and source may be the same buffer
*/
char *uri_unescape(char *dest, size_t dest_len, const char *src, int src_len);

unsigned html_escape_len(const char *s, size_t len);
void html_escape(char *dest, size_t len, const char *s);


/** @brief Replace a nul-terminated string with its unescaped version
* @param str the string to un-escape
* @retval char* the result, a copy of str
* @note unescaped string is never longer than escaped version
*/
char* uri_unescape_inplace(char *str);

/** @brief escape the given URI string
* @param src
* @param src_len
Expand All @@ -24,18 +62,19 @@ static inline String uri_escape(const String& src)
}


/** @brief replace the given uri by its unescaped version
* @retval int length of result
/** @brief replace the given text by its unescaped version
* @param str the string to unescape
* @retval reference to str, unescaped
* @note unescaped string is never longer than escaped version
*/
int uri_unescape_inplace(String& s);
String& uri_unescape_inplace(String& str);

/** @brief return the unescaped version of a string
* @retval String unescaped string
*/
static inline String uri_unescape(const String& s)
static inline String uri_unescape(const String& str)
{
String ret = s;
String ret = str;
uri_unescape_inplace(ret);
return ret;
}
Expand Down
10 changes: 2 additions & 8 deletions Sming/SmingCore/Data/Stream/UrlencodedOutputStream.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,10 @@

/*
* @todo Revise this so stream produces encoded output line-by-line, rather than all at once.
* Can use StreamTransformer to do this.
*/

UrlencodedOutputStream::UrlencodedOutputStream(const HttpParams& params)
{
for(unsigned i = 0; i < params.count(); i++) {
if(i > 0)
stream.write('&');

stream.print(uri_escape(params.keyAt(i)));
stream.print('=');
stream.print(uri_escape(params.valueAt(i)));
}
stream.print(params);
}
6 changes: 2 additions & 4 deletions Sming/SmingCore/Data/Stream/UrlencodedOutputStream.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,14 @@
#define _SMING_CORE_DATA_URL_ENCODDED_OUTPUT_STREAM_H_

#include "MemoryDataStream.h"
#include "WHashMap.h"
#include "Network/Http/HttpParams.h"

/**
* @brief UrlEncoded Stream
* @ingroup stream data
*
* @{
*/

typedef HashMap<String, String> HttpParams;
*/

class UrlencodedOutputStream : public ReadWriteStream
{
Expand Down
2 changes: 0 additions & 2 deletions Sming/SmingCore/Data/Structures.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,4 @@ template <typename T, int rawSize> class SimpleConcurrentQueue : public FIFO<T,
}
};

typedef HashMap<String, String> HttpParams;

#endif /* _SMING_CORE_DATA_STRUCTURES_H_ */
28 changes: 14 additions & 14 deletions Sming/SmingCore/Network/Http/HttpConnection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -476,24 +476,24 @@ void HttpConnection::sendRequestHeaders(HttpRequest* request)
new MultipartStream(HttpPartProducerDelegate(&HttpConnection::multipartProducer, this));
request->headers[HTTP_HEADER_CONTENT_TYPE] =
ContentType::toString(MIME_FORM_MULTIPART) + _F("; boundary=") + mStream->getBoundary();
if(request->stream) {
if(request->bodyStream) {
debug_e("HttpConnection: existing stream is discarded due to POST params");
delete request->stream;
delete request->bodyStream;
}
request->stream = mStream;
request->bodyStream = mStream;
} else if(request->postParams.count()) {
UrlencodedOutputStream* uStream = new UrlencodedOutputStream(request->postParams);
request->headers[HTTP_HEADER_CONTENT_TYPE] = ContentType::toString(MIME_FORM_URL_ENCODED);
if(request->stream) {
if(request->bodyStream) {
debug_e("HttpConnection: existing stream is discarded due to POST params");
delete request->stream;
delete request->bodyStream;
}
request->stream = uStream;
request->bodyStream = uStream;
} /* if (request->postParams.count()) */

if(request->stream != nullptr) {
if(request->stream->available() > -1) {
request->headers[HTTP_HEADER_CONTENT_LENGTH] = String(request->stream->available());
if(request->bodyStream != nullptr) {
if(request->bodyStream->available() > -1) {
request->headers[HTTP_HEADER_CONTENT_LENGTH] = String(request->bodyStream->available());
} else {
request->headers.remove(HTTP_HEADER_CONTENT_LENGTH);
}
Expand All @@ -515,17 +515,17 @@ bool HttpConnection::sendRequestBody(HttpRequest* request)
if(state == eHCS_StartBody) {
state = eHCS_SendingBody;

if(request->stream == nullptr) {
if(request->bodyStream == nullptr) {
return true;
}

delete stream;
if(request->headers[HTTP_HEADER_TRANSFER_ENCODING] == _F("chunked")) {
stream = new ChunkedStream(request->stream);
stream = new ChunkedStream(request->bodyStream);
} else {
stream = request->stream; // avoid intermediate buffers
stream = request->bodyStream; // avoid intermediate buffers
}
request->stream = nullptr;
request->bodyStream = nullptr;
return false;
}

Expand All @@ -534,7 +534,7 @@ bool HttpConnection::sendRequestBody(HttpRequest* request)
return true;
}

if(request->stream == nullptr && !stream->isFinished()) {
if(request->bodyStream == nullptr && !stream->isFinished()) {
return false;
}

Expand Down
27 changes: 27 additions & 0 deletions Sming/SmingCore/Network/Http/HttpParams.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/****
* Sming Framework Project - Open Source framework for high efficiency native ESP8266 development.
* Created 2015 by Skurydin Alexey
* http://github.com/SmingHub/Sming
* All files of the Sming Core are provided under the LGPL v3 license.
*
* @author: 2018 - Mikee47 <[email protected]>
*
****/

#include "HttpParams.h"
#include "../Services/WebHelpers/escape.h"
#include "Print.h"

size_t HttpParams::printTo(Print& p) const
{
size_t charsPrinted = 0;
for(unsigned i = 0; i < count(); i++) {
if(i > 0)
charsPrinted += p.print('&');
charsPrinted += p.print(uri_escape(keyAt(i)));
charsPrinted += p.print('=');
charsPrinted += p.print(uri_escape(valueAt(i)));
}

return charsPrinted;
}
37 changes: 37 additions & 0 deletions Sming/SmingCore/Network/Http/HttpParams.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/****
* Sming Framework Project - Open Source framework for high efficiency native ESP8266 development.
* Created 2015 by Skurydin Alexey
* http://github.com/SmingHub/Sming
* All files of the Sming Core are provided under the LGPL v3 license.
*
* @author: 2018 - Mikee47 <[email protected]>
*
* Class to manage HTTP URI query parameters
*
* The HttpParams class was an empty HashMap class living in 'Structures.h'.
* It has been expanded to incorporate escaping and unescaping.
* Custom URL parsing code has been replaced with the yuarel library https://github.com/jacketizer/libyuarel
*
****/

#ifndef _SMINGCORE_HTTP_HTTP_PARAMS_H_
#define _SMINGCORE_HTTP_HTTP_PARAMS_H_

#include "WString.h"
#include "WHashMap.h"
#include "Printable.h"

/** @brief
*
* @todo values stored in escaped form, unescape return value and escape provided values.
* Revise HttpBodyParser.cpp as it will no longer do this job.
*
*/
class HttpParams : public HashMap<String, String>, public Printable
{
public:
// Printable
virtual size_t printTo(Print& p) const;
};

#endif // _SMINGCORE_HTTP_HTTP_PARAMS_H_
Loading