Skip to content

Commit

Permalink
Separate HttpParams class and fix escaping
Browse files Browse the repository at this point in the history
WebHelpers/escape
* bugfix: encoding of space as '+' added
* uri_escape(const char*, int) rewritten without using heap
* add uri_unescape_inplace(char*, int)
* bugfix: output buffer must account for nul terminator in uri_unescape_inplace(String&)

structures.h
* Move HttpParams definition into separate module

UrlencodedOutputStream
* Remove (duplicate) definition of HttpParams
* Move output code into HttpParams::printTo() method
  • Loading branch information
mikee47 committed Oct 21, 2018
1 parent a2aba30 commit b4a1117
Show file tree
Hide file tree
Showing 8 changed files with 141 additions and 32 deletions.
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_ */
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_
1 change: 1 addition & 0 deletions Sming/SmingCore/Network/Http/HttpRequest.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "Data/Stream/DataSourceStream.h"
#include "Data/Stream/MultipartStream.h"
#include "Network/Http/HttpHeaders.h"
#include "HttpParams.h"

class HttpClient;
class HttpServerConnection;
Expand Down

0 comments on commit b4a1117

Please sign in to comment.