@@ -20,6 +20,7 @@ | |||
#define CPPCMS_JSON_H | |||
#include <cppcms/defs.h> | |||
#include <cppcms/string_key.h> | |||
#include <booster/copy_ptr.h> | |||
#include <booster/backtrace.h> | |||
#include <vector> | |||
@@ -60,7 +61,7 @@ namespace json { | |||
/// | |||
/// The json::object - std::map of json::value's | |||
/// | |||
typedef std::map<std::string,value> object; | |||
typedef std::map<string_key,value> object; | |||
#ifdef CPPCMS_DOXYGEN_DOCS | |||
@@ -263,6 +264,14 @@ namespace json { | |||
/// that holds an object { "y" : 10 } and find("foo") would return value of undefined type. | |||
/// | |||
value const &find(std::string const &path) const; | |||
/// | |||
/// Searches a value in the path \a path | |||
/// | |||
/// For example if the json::value represents { "x" : { "y" : 10 } }, then find("x.y") would return | |||
/// a reference to value that hold a number 10, find("x") returns a reference to a value | |||
/// that holds an object { "y" : 10 } and find("foo") would return value of undefined type. | |||
/// | |||
value const &find(char const *path) const; | |||
/// | |||
/// Searches a value in the path \a path, if not found throw bad_value_cast. | |||
@@ -279,12 +288,32 @@ namespace json { | |||
/// a reference to value that hold a number 10, find("x") returns a reference to a value | |||
/// that holds an object { "y" : 10 } and find("foo") throws | |||
/// | |||
value const &at(char const *path) const; | |||
/// | |||
/// Searches a value in the path \a path, if not found throw bad_value_cast. | |||
/// | |||
/// For example if the json::value represents { "x" : { "y" : 10 } }, then find("x.y") would return | |||
/// a reference to value that hold a number 10, find("x") returns a reference to a value | |||
/// that holds an object { "y" : 10 } and find("foo") throws | |||
/// | |||
value &at(std::string const &path); | |||
/// | |||
/// Searches a value in the path \a path, if not found throw bad_value_cast. | |||
/// | |||
/// For example if the json::value represents { "x" : { "y" : 10 } }, then find("x.y") would return | |||
/// a reference to value that hold a number 10, find("x") returns a reference to a value | |||
/// that holds an object { "y" : 10 } and find("foo") throws | |||
/// | |||
value &at(char const *path); | |||
/// | |||
/// Sets the value \a v at the path \a path, if the path invalid, creates it. | |||
/// | |||
void at(std::string const &path,value const &v); | |||
/// | |||
/// Sets the value \a v at the path \a path, if the path invalid, creates it. | |||
/// | |||
void at(char const *path,value const &v); | |||
/// | |||
@@ -305,6 +334,15 @@ namespace json { | |||
{ | |||
return find(path).type(); | |||
} | |||
/// | |||
/// Returns the type of variable in path, if not found returns undefined | |||
/// | |||
/// Same as find(path).type() | |||
/// | |||
json_type type(char const *path) const | |||
{ | |||
return find(path).type(); | |||
} | |||
/// | |||
/// Convert an object \a v of type T to a value at specific path, same as at(path,value(v)) | |||
@@ -314,6 +352,14 @@ namespace json { | |||
{ | |||
at(path,value(v)); | |||
} | |||
/// | |||
/// Convert an object \a v of type T to a value at specific path, same as at(path,value(v)) | |||
/// | |||
template<typename T> | |||
void set(char const *path,T const &v) | |||
{ | |||
at(path,value(v)); | |||
} | |||
/// | |||
/// Get a string value from a path \a path. If the path is not invalid or the object | |||
@@ -331,6 +377,22 @@ namespace json { | |||
return def; | |||
} | |||
} | |||
/// | |||
/// Get a string value from a path \a path. If the path is not invalid or the object | |||
/// is not of type string at this path, returns \a def instead | |||
/// | |||
std::string get(char const *path,char const *def) const | |||
{ | |||
value const &v=find(path); | |||
if(v.is_undefined()) | |||
return def; | |||
try { | |||
return v.get_value<std::string>(); | |||
} | |||
catch(std::bad_cast const &e) { | |||
return def; | |||
} | |||
} | |||
/// | |||
/// Get an object of type T from the path \a path. Throws bad_value_cast if such path does not | |||
@@ -341,12 +403,38 @@ namespace json { | |||
{ | |||
return at(path).get_value<T>(); | |||
} | |||
/// | |||
/// Get an object of type T from the path \a path. Throws bad_value_cast if such path does not | |||
/// exists of conversion can't be done | |||
/// | |||
template<typename T> | |||
T get(char const *path) const | |||
{ | |||
return at(path).get_value<T>(); | |||
} | |||
/// | |||
/// Get an object of type T from the path \a path. Returns \a def if such path does not | |||
/// exists of conversion can't be done | |||
/// | |||
template<typename T> | |||
T get(char const *path,T const &def) const | |||
{ | |||
value const &v=find(path); | |||
if(v.is_undefined()) | |||
return def; | |||
try { | |||
return v.get_value<T>(); | |||
} | |||
catch(std::bad_cast const &e) { | |||
return def; | |||
} | |||
} | |||
/// | |||
/// Get an object of type T from the path \a path. Returns \a def if such path does not | |||
/// exists of conversion can't be done | |||
/// | |||
template<typename T> | |||
T get(std::string const &path,T const &def) const | |||
{ | |||
value const &v=find(path); | |||
@@ -0,0 +1,117 @@ | |||
/////////////////////////////////////////////////////////////////////////////// | |||
// | |||
// Copyright (C) 2008-2010 Artyom Beilis (Tonkikh) <artyomtnk@yahoo.com> | |||
// | |||
// This program is free software: you can redistribute it and/or modify | |||
// it under the terms of the GNU Lesser General Public License as published by | |||
// the Free Software Foundation, either version 3 of the License, or | |||
// (at your option) any later version. | |||
// | |||
// This program is distributed in the hope that it will be useful, | |||
// but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
// GNU Lesser General Public License for more details. | |||
// | |||
// You should have received a copy of the GNU Lesser General Public License | |||
// along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
// | |||
/////////////////////////////////////////////////////////////////////////////// | |||
#ifndef CPPCMS_STEAL_BUF_H | |||
#define CPPCMS_STEAL_BUF_H | |||
#include <streambuf> | |||
#include <ostream> | |||
#include <stdio.h> | |||
#include <string> | |||
#include <string.h> | |||
#include <stdlib.h> | |||
namespace cppcms { | |||
namespace util { | |||
template<size_t on_stack_size = 128> | |||
class steal_buffer : public std::streambuf { | |||
steal_buffer(steal_buffer const &); | |||
void operator=(steal_buffer const &); | |||
public: | |||
char *begin() | |||
{ | |||
return pbase(); | |||
} | |||
char *end() | |||
{ | |||
return pptr(); | |||
} | |||
steal_buffer(std::ostream &out) | |||
{ | |||
init(); | |||
steal(out); | |||
} | |||
steal_buffer() | |||
{ | |||
init(); | |||
} | |||
void steal(std::ostream &out) | |||
{ | |||
release(); | |||
stolen_ = out.rdbuf(this); | |||
stream_ = &out; | |||
} | |||
void release() | |||
{ | |||
if(stream_ && stolen_) { | |||
stream_->rdbuf(stolen_); | |||
} | |||
stream_ = 0; | |||
stolen_ = 0; | |||
} | |||
~steal_buffer() | |||
{ | |||
release(); | |||
free(on_heap_); | |||
} | |||
int overflow(int c) | |||
{ | |||
size_t current_size; | |||
size_t new_size; | |||
if(pbase() == on_stack_) { | |||
current_size = on_stack_size; | |||
new_size = on_stack_size * 2; | |||
on_heap_ = (char *)malloc(new_size); | |||
if(!on_heap_) | |||
throw std::bad_alloc(); | |||
memcpy(on_heap_,on_stack_,current_size); | |||
} | |||
else { | |||
current_size = pptr() - pbase(); | |||
new_size = current_size * 2; | |||
char *new_ptr = (char *)realloc(on_heap_,new_size); | |||
if(!new_ptr) | |||
throw std::bad_alloc(); | |||
on_heap_ = new_ptr; | |||
} | |||
setp(on_heap_,on_heap_ + new_size); | |||
pbump(current_size); | |||
if(c!=EOF) | |||
sputc(c); | |||
return 0; | |||
} | |||
private: | |||
void init() | |||
{ | |||
on_heap_ = 0; | |||
stolen_ = 0; | |||
stream_ = 0; | |||
setp(on_stack_,on_stack_+on_stack_size); | |||
} | |||
char *on_heap_; | |||
std::streambuf *stolen_; | |||
std::ostream *stream_; | |||
char on_stack_[on_stack_size]; | |||
}; | |||
} // util | |||
} // cppcms | |||
#endif |
@@ -0,0 +1,330 @@ | |||
/////////////////////////////////////////////////////////////////////////////// | |||
// | |||
// Copyright (C) 2008-2010 Artyom Beilis (Tonkikh) <artyomtnk@yahoo.com> | |||
// | |||
// This program is free software: you can redistribute it and/or modify | |||
// it under the terms of the GNU Lesser General Public License as published by | |||
// the Free Software Foundation, either version 3 of the License, or | |||
// (at your option) any later version. | |||
// | |||
// This program is distributed in the hope that it will be useful, | |||
// but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
// GNU Lesser General Public License for more details. | |||
// | |||
// You should have received a copy of the GNU Lesser General Public License | |||
// along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
// | |||
/////////////////////////////////////////////////////////////////////////////// | |||
#ifndef CPPCMS_STRING_KEY_H | |||
#define CPPCMS_STRING_KEY_H | |||
#include <string> | |||
#include <string.h> | |||
#include <algorithm> | |||
#include <stdexcept> | |||
#include <ostream> | |||
namespace cppcms { | |||
class string_key { | |||
public: | |||
typedef char const *const_iterator; | |||
static const size_t npos = std::string::npos; | |||
string_key() : | |||
begin_(0), | |||
end_(0) | |||
{ | |||
} | |||
string_key(char const *key) : | |||
begin_(0), | |||
end_(0), | |||
key_(key) | |||
{ | |||
} | |||
string_key(std::string const &key) : | |||
begin_(0), | |||
end_(0), | |||
key_(key) | |||
{ | |||
} | |||
size_t size() const | |||
{ | |||
return end() - begin(); | |||
} | |||
size_t length() const | |||
{ | |||
return size(); | |||
} | |||
void clear() | |||
{ | |||
begin_ = end_ = 0; | |||
key_.clear(); | |||
} | |||
bool empty() const | |||
{ | |||
return end() == begin(); | |||
} | |||
size_t find(char c,size_t pos = 0) const | |||
{ | |||
size_t s = size(); | |||
if(pos >= s) | |||
return npos; | |||
char const *p=begin() + pos; | |||
while(pos <= s && *p!=c) { | |||
pos++; | |||
p++; | |||
} | |||
if(pos >= s) | |||
return npos; | |||
return pos; | |||
} | |||
string_key substr(size_t pos = 0,size_t n=npos) const | |||
{ | |||
string_key tmp = unowned_substr(pos,n); | |||
return string_key(std::string(tmp.begin(),tmp.end())); | |||
} | |||
string_key unowned_substr(size_t pos = 0,size_t n=npos) const | |||
{ | |||
if(pos >= size()) { | |||
return string_key(); | |||
} | |||
char const *p=begin() + pos; | |||
char const *e=end(); | |||
if(n > size_t(e-p)) { | |||
return string_key(p,e); | |||
} | |||
else { | |||
return string_key(p,p+n); | |||
} | |||
} | |||
char const &operator[](size_t n) const | |||
{ | |||
return *(begin() + n); | |||
} | |||
char const &at(size_t n) const | |||
{ | |||
if(n > size()) | |||
throw std::out_of_range("cppcms::string_key::at() range error"); | |||
return *(begin() + n); | |||
} | |||
static string_key unowned(std::string const &v) | |||
{ | |||
return string_key(v.c_str(),v.c_str()+v.size()); | |||
} | |||
static string_key unowned(char const *str) | |||
{ | |||
char const *end = str; | |||
while(*end) | |||
end++; | |||
return string_key(str,end); | |||
} | |||
static string_key unowned(char const *begin,char const *end) | |||
{ | |||
return string_key(begin,end); | |||
} | |||
char const *begin() const | |||
{ | |||
if(begin_) | |||
return begin_; | |||
return key_.c_str(); | |||
} | |||
char const *end() const | |||
{ | |||
if(begin_) | |||
return end_; | |||
return key_.c_str() + key_.size(); | |||
} | |||
bool operator<(string_key const &other) const | |||
{ | |||
return std::lexicographical_compare( begin(),end(), | |||
other.begin(),other.end(), | |||
std::char_traits<char>::lt); | |||
} | |||
bool operator>(string_key const &other) const | |||
{ | |||
return other < *this; | |||
} | |||
bool operator>=(string_key const &other) const | |||
{ | |||
return !(*this < other); | |||
} | |||
bool operator<=(string_key const &other) const | |||
{ | |||
return !(*this > other); | |||
} | |||
bool operator==(string_key const &other) const | |||
{ | |||
return (end() - begin() == other.end() - other.begin()) | |||
&& memcmp(begin(),other.begin(),end()-begin()) == 0; | |||
} | |||
bool operator!=(string_key const &other) const | |||
{ | |||
return !(*this!=other); | |||
} | |||
char const *data() const | |||
{ | |||
return begin(); | |||
} | |||
std::string str() const | |||
{ | |||
if(begin_) | |||
return std::string(begin_,end_-begin_); | |||
else | |||
return key_; | |||
} | |||
operator std::string() const | |||
{ | |||
return str(); | |||
} | |||
private: | |||
string_key(char const *b,char const *e) : | |||
begin_(b), | |||
end_(e) | |||
{ | |||
} | |||
char const *begin_; | |||
char const *end_; | |||
std::string key_; | |||
}; | |||
inline std::ostream &operator<<(std::ostream &out,string_key const &s) | |||
{ | |||
out.write(s.data(),s.size()); | |||
return out; | |||
} | |||
inline bool operator==(string_key const &l,char const *r) | |||
{ | |||
return l==string_key::unowned(r); | |||
} | |||
inline bool operator==(char const *l,string_key const &r) | |||
{ | |||
return string_key::unowned(l) == r; | |||
} | |||
inline bool operator==(string_key const &l,std::string const &r) | |||
{ | |||
return l==string_key::unowned(r); | |||
} | |||
inline bool operator==(std::string const &l,string_key const &r) | |||
{ | |||
return string_key::unowned(l) == r; | |||
} | |||
inline bool operator!=(string_key const &l,char const *r) | |||
{ | |||
return l!=string_key::unowned(r); | |||
} | |||
inline bool operator!=(char const *l,string_key const &r) | |||
{ | |||
return string_key::unowned(l) != r; | |||
} | |||
inline bool operator!=(string_key const &l,std::string const &r) | |||
{ | |||
return l!=string_key::unowned(r); | |||
} | |||
inline bool operator!=(std::string const &l,string_key const &r) | |||
{ | |||
return string_key::unowned(l) != r; | |||
} | |||
inline bool operator<=(string_key const &l,char const *r) | |||
{ | |||
return l<=string_key::unowned(r); | |||
} | |||
inline bool operator<=(char const *l,string_key const &r) | |||
{ | |||
return string_key::unowned(l) <= r; | |||
} | |||
inline bool operator<=(string_key const &l,std::string const &r) | |||
{ | |||
return l<=string_key::unowned(r); | |||
} | |||
inline bool operator<=(std::string const &l,string_key const &r) | |||
{ | |||
return string_key::unowned(l) <= r; | |||
} | |||
inline bool operator>=(string_key const &l,char const *r) | |||
{ | |||
return l>=string_key::unowned(r); | |||
} | |||
inline bool operator>=(char const *l,string_key const &r) | |||
{ | |||
return string_key::unowned(l) >= r; | |||
} | |||
inline bool operator>=(string_key const &l,std::string const &r) | |||
{ | |||
return l>=string_key::unowned(r); | |||
} | |||
inline bool operator>=(std::string const &l,string_key const &r) | |||
{ | |||
return string_key::unowned(l) >= r; | |||
} | |||
inline bool operator<(string_key const &l,char const *r) | |||
{ | |||
return l<string_key::unowned(r); | |||
} | |||
inline bool operator<(char const *l,string_key const &r) | |||
{ | |||
return string_key::unowned(l) < r; | |||
} | |||
inline bool operator<(string_key const &l,std::string const &r) | |||
{ | |||
return l<string_key::unowned(r); | |||
} | |||
inline bool operator<(std::string const &l,string_key const &r) | |||
{ | |||
return string_key::unowned(l) < r; | |||
} | |||
inline bool operator>(string_key const &l,char const *r) | |||
{ | |||
return l>string_key::unowned(r); | |||
} | |||
inline bool operator>(char const *l,string_key const &r) | |||
{ | |||
return string_key::unowned(l) > r; | |||
} | |||
inline bool operator>(string_key const &l,std::string const &r) | |||
{ | |||
return l>string_key::unowned(r); | |||
} | |||
inline bool operator>(std::string const &l,string_key const &r) | |||
{ | |||
return string_key::unowned(l) > r; | |||
} | |||
} | |||
#endif |
@@ -20,6 +20,7 @@ | |||
#define CPPCMS_URL_MAPPER_H | |||
#include <cppcms/defs.h> | |||
#include <cppcms/string_key.h> | |||
#include <booster/noncopyable.h> | |||
#include <booster/hold_ptr.h> | |||
#include <cppcms/filters.h> | |||
@@ -233,6 +234,66 @@ namespace cppcms { | |||
/// Write the URL to output stream \a out for the URL \a path with 0 parameters | |||
/// | |||
void map( std::ostream &out, | |||
char const *path); | |||
/// | |||
/// Write the URL to output stream \a out for the URL \a path with 1 parameters | |||
/// | |||
void map( std::ostream &out, | |||
char const *path, | |||
filters::streamable const &p1); | |||
/// | |||
/// Write the URL to output stream \a out for the URL \a path with 2 parameters | |||
/// | |||
void map( std::ostream &out, | |||
char const *path, | |||
filters::streamable const &p1, | |||
filters::streamable const &p2); | |||
/// | |||
/// Write the URL to output stream \a out for the URL \a path with 3 parameters | |||
/// | |||
void map( std::ostream &out, | |||
char const *path, | |||
filters::streamable const &p1, | |||
filters::streamable const &p2, | |||
filters::streamable const &p3); | |||
/// | |||
/// Write the URL to output stream \a out for the URL \a path with 4 parameters | |||
/// | |||
void map( std::ostream &out, | |||
char const *path, | |||
filters::streamable const &p1, | |||
filters::streamable const &p2, | |||
filters::streamable const &p3, | |||
filters::streamable const &p4); | |||
/// | |||
/// Write the URL to output stream \a out for the URL \a path with 5 parameters | |||
/// | |||
void map( std::ostream &out, | |||
char const *path, | |||
filters::streamable const &p1, | |||
filters::streamable const &p2, | |||
filters::streamable const &p3, | |||
filters::streamable const &p4, | |||
filters::streamable const &p5); | |||
/// | |||
/// Write the URL to output stream \a out for the URL \a path with 6 parameters | |||
/// | |||
void map( std::ostream &out, | |||
char const *path, | |||
filters::streamable const &p1, | |||
filters::streamable const &p2, | |||
filters::streamable const &p3, | |||
filters::streamable const &p4, | |||
filters::streamable const &p5, | |||
filters::streamable const &p6); | |||
/// | |||
/// Write the URL to output stream \a out for the URL \a path with 0 parameters | |||
/// | |||
void map( std::ostream &out, | |||
std::string const &path); | |||
/// | |||
@@ -314,9 +375,9 @@ namespace cppcms { | |||
private: | |||
void real_assign(std::string const &key,std::string const &url,application *child = 0); | |||
url_mapper &get_mapper_for_key(std::string const &key,std::string &real_key,std::vector<std::string> &direct); | |||
url_mapper &get_mapper_for_key(string_key const &key,string_key &real_key,std::vector<string_key> &direct); | |||
url_mapper *root_mapper(); | |||
void real_map( std::string const &key, | |||
void real_map( char const *key, | |||
filters::streamable const *const *params, | |||
size_t params_no, | |||
std::ostream &output); | |||
@@ -42,10 +42,26 @@ namespace cppcms { | |||
/// | |||
std::string CPPCMS_API escape(std::string const &s); | |||
/// | |||
/// Escape string for inclusion in HTML page, i.e. | |||
/// | |||
/// - < - \< | |||
/// - > - \> | |||
/// - \& - \& | |||
/// - " - \" | |||
/// | |||
/// Note, this function does not deal with encodings, so it's up to you to | |||
/// provide valid text encoding | |||
/// | |||
void CPPCMS_API escape(char const *begin,char const *end,std::ostream &output); | |||
/// | |||
/// Encode string for URL (percent encoding) | |||
/// | |||
std::string CPPCMS_API urlencode(std::string const &s); | |||
/// | |||
/// Encode string for URL (percent encoding) | |||
/// | |||
void CPPCMS_API urlencode(char const *begin,char const *end,std::ostream &output); | |||
/// | |||
/// Decode string from URL-encoding (percent-encoding) | |||
/// | |||
std::string CPPCMS_API urldecode(std::string const &s); | |||
@@ -18,6 +18,7 @@ | |||
/////////////////////////////////////////////////////////////////////////////// | |||
#define CPPCMS_SOURCE | |||
#include <cppcms/filters.h> | |||
#include <cppcms/steal_buf.h> | |||
#include <cppcms/base64.h> | |||
#include <cppcms/util.h> | |||
#include <iostream> | |||
@@ -135,7 +136,10 @@ namespace cppcms { namespace filters { | |||
escape const &escape::operator=(escape const &other){ obj_ = other.obj_; return *this; } | |||
void escape::operator()(std::ostream &out) const | |||
{ | |||
out << util::escape(obj_.get(out)); | |||
util::steal_buffer<> sb(out); | |||
obj_(out); | |||
sb.release(); | |||
util::escape(sb.begin(),sb.end(),out); | |||
} | |||
struct urlencode::_data {}; | |||
@@ -146,7 +150,10 @@ namespace cppcms { namespace filters { | |||
urlencode const &urlencode::operator=(urlencode const &other){ obj_ = other.obj_; return *this; } | |||
void urlencode::operator()(std::ostream &out) const | |||
{ | |||
out << util::urlencode(obj_.get(out)); | |||
util::steal_buffer<> sb(out); | |||
obj_(out); | |||
sb.release(); | |||
util::urlencode(sb.begin(),sb.end(),out); | |||
} | |||
struct raw::_data {}; | |||
@@ -402,15 +402,16 @@ namespace json { | |||
// returns empty if not found | |||
value const &value::find(std::string const &path) const | |||
value const &value::find(char const *cpath) const | |||
{ | |||
string_key path=string_key::unowned(cpath); | |||
static value const empty; | |||
value const *ptr=this; | |||
size_t pos=0; | |||
size_t new_pos; | |||
do { | |||
new_pos=path.find('.',pos); | |||
std::string const part=path.substr(pos,new_pos - pos); | |||
string_key const part=path.unowned_substr(pos,new_pos - pos); | |||
if(new_pos!=std::string::npos) | |||
new_pos++; | |||
if(part.empty()) | |||
@@ -427,23 +428,37 @@ namespace json { | |||
} while(new_pos < path.size()); | |||
return *ptr; | |||
} | |||
// returns empty if not found | |||
value const &value::find(std::string const &path) const | |||
{ | |||
return find(path.c_str()); | |||
} | |||
// throws if not found | |||
value const &value::at(std::string const &path) const | |||
{ | |||
return at(path.c_str()); | |||
} | |||
value const &value::at(char const *path) const | |||
{ | |||
value const &v=find(path); | |||
if(v.is_undefined()) | |||
throw bad_value_cast("Value not found at "+path ); | |||
throw bad_value_cast(std::string("Value not found at ")+path ); | |||
return v; | |||
} | |||
value &value::at(std::string const &path) | |||
{ | |||
return at(path.c_str()); | |||
} | |||
value &value::at(char const *cpath) | |||
{ | |||
string_key path=string_key::unowned(cpath); | |||
value *ptr=this; | |||
size_t pos=0; | |||
size_t new_pos; | |||
do { | |||
new_pos=path.find('.',pos); | |||
std::string part=path.substr(pos,new_pos - pos); | |||
string_key part=path.unowned_substr(pos,new_pos - pos); | |||
if(new_pos!=std::string::npos) | |||
new_pos++; | |||
if(part.empty()) | |||
@@ -453,7 +468,7 @@ namespace json { | |||
json::object &obj=ptr->object(); | |||
json::object::iterator p; | |||
if((p=obj.find(part))==obj.end()) | |||
throw bad_value_cast("Member "+part+" not found"); | |||
throw bad_value_cast("Member "+part.str()+" not found"); | |||
ptr=&p->second; | |||
pos=new_pos; | |||
@@ -462,12 +477,17 @@ namespace json { | |||
} | |||
void value::at(std::string const &path,value const &v) | |||
{ | |||
at(path.c_str(),v); | |||
} | |||
void value::at(char const *cpath,value const &v) | |||
{ | |||
string_key path=string_key::unowned(cpath); | |||
value *ptr=this; | |||
size_t pos=0; | |||
size_t new_pos; | |||
do { | |||
new_pos=path.find('.',pos); | |||
std::string part=path.substr(pos,new_pos - pos); | |||
string_key part=path.unowned_substr(pos,new_pos - pos); | |||
if(new_pos!=std::string::npos) | |||
@@ -480,7 +500,7 @@ namespace json { | |||
json::object &obj=ptr->object(); | |||
json::object::iterator p; | |||
if((p=obj.find(part))==obj.end()) { | |||
ptr=&obj.insert(std::make_pair(part,json::value())).first->second; | |||
ptr=&obj.insert(std::make_pair(part.str(),json::value())).first->second; | |||
} | |||
else | |||
ptr=&p->second; | |||
@@ -497,7 +517,7 @@ namespace json { | |||
json::object &self=object(); | |||
json::object::iterator p=self.find(name); | |||
json::object::iterator p=self.find(string_key::unowned(name)); | |||
if(p==self.end()) | |||
return self.insert(std::make_pair(name,value())).first->second; | |||
return p->second; | |||
@@ -508,7 +528,7 @@ namespace json { | |||
if(type()!=json::is_object) | |||
throw bad_value_cast("",type(),json::is_object); | |||
json::object const &self=object(); | |||
json::object::const_iterator p=self.find(name); | |||
json::object::const_iterator p=self.find(string_key::unowned(name)); | |||
if(p==self.end()) | |||
throw bad_value_cast("Member "+name+" not found"); | |||
return p->second; | |||
@@ -27,8 +27,32 @@ | |||
#include <iostream> | |||
namespace cppcms { | |||
template<typename Data,typename Entry> | |||
struct stream_it { | |||
Data const *self; | |||
Entry const &formatting; | |||
filters::streamable const * const *params; | |||
size_t params_no; | |||
std::map<string_key,std::string> const &data_helpers_default; | |||
std::map<string_key,std::string> const &data_helpers_override; | |||
void write(std::ostream &out) const | |||
{ | |||
self->write(formatting,params,params_no,data_helpers_default,data_helpers_override,out); | |||
} | |||
}; | |||
template<typename Data,typename Entry> | |||
std::ostream &operator<<(std::ostream &out,stream_it<Data,Entry> const &wr) | |||
{ | |||
wr.write(out); | |||
return out; | |||
} | |||
struct url_mapper::data | |||
{ | |||
data() : parent(0),this_application(0) {} | |||
std::string this_name; | |||
application *parent; | |||
@@ -41,29 +65,32 @@ namespace cppcms { | |||
application *child; | |||
entry() : child(0) {} | |||
}; | |||
template<typename Data,typename Entry> | |||
friend struct stream_it; | |||
typedef std::map<size_t,entry> by_size_type; | |||
typedef std::map<std::string,by_size_type> by_key_type; | |||
typedef std::map<std::string,std::string> helpers_type; | |||
typedef std::map<string_key,by_size_type> by_key_type; | |||
typedef std::map<string_key,std::string> helpers_type; | |||
by_key_type by_key; | |||
helpers_type helpers; | |||
std::string root; | |||
entry const &get_entry(std::string const &key,size_t params_no,std::string const &full_url) const | |||
entry const &get_entry(string_key const &key,size_t params_no,string_key const &full_url) const | |||
{ | |||
by_key_type::const_iterator kp = by_key.find(key); | |||
if(kp == by_key.end()) | |||
throw cppcms_error("url_mapper: key `" + key + "' not found for " | |||
"url `" + full_url + "'"); | |||
throw cppcms_error("url_mapper: key `" + key.str() + "' not found for " | |||
"url `" + full_url.str() + "'"); | |||
by_size_type::const_iterator sp = kp->second.find(params_no); | |||
if(sp == kp->second.end()) | |||
throw cppcms_error("url_mapper: invalid number of parameters for " + key + | |||
"in url `" + full_url + "'"); | |||
throw cppcms_error("url_mapper: invalid number of parameters for " + key.str() + | |||
"in url `" + full_url.str() + "'"); | |||
return sp->second; | |||
} | |||
url_mapper *is_app(std::string const &key) const | |||
url_mapper *is_app(string_key const &key) const | |||
{ | |||
by_key_type::const_iterator kp = by_key.find(key); | |||
if(kp == by_key.end()) | |||
@@ -76,52 +103,44 @@ namespace cppcms { | |||
return 0; | |||
} | |||
url_mapper &child(std::string const &name,std::string const &full_url) | |||
url_mapper &child(string_key const &name,string_key const &full_url) | |||
{ | |||
entry const &fmt = get_entry(name,1,full_url); | |||
if(!fmt.child) { | |||
throw cppcms_error("url_mapper: the key " + name + " is not child application key" | |||
" in url `" + full_url + "'"); | |||
throw cppcms_error("url_mapper: the key " + name.str() + " is not child application key" | |||
" in url `" + full_url.str() + "'"); | |||
} | |||
return fmt.child->mapper(); | |||
} | |||
void map( std::string const &key, | |||
std::string const &full_url, | |||
struct map_stream { | |||
filters::streamable const * const *params; | |||
size_t params_no; | |||
std::map<string_key,std::string> const &data_helpers_default; | |||
std::map<string_key,std::string> const &data_helpers_override; | |||
}; | |||
void write( entry const &formatting, | |||
filters::streamable const * const *params, | |||
size_t params_no, | |||
std::map<std::string,std::string> const &data_helpers_default, | |||
std::map<std::string,std::string> const &data_helpers_override, | |||
std::ostream &output) const | |||
std::map<string_key,std::string> const &data_helpers_default, | |||
std::map<string_key,std::string> const &data_helpers_override, | |||
std::ostream &out) const | |||
{ | |||
entry const &formatting = get_entry(key,params_no,full_url); | |||
std::ostringstream ss; | |||
std::ostream *out = 0; | |||
if(parent) { | |||
ss.copyfmt(output); | |||
out = &ss; | |||
} | |||
else { | |||
out = &output; | |||
*out << root; | |||
} | |||
for(size_t i=0;i<formatting.parts.size();i++) { | |||
*out << formatting.parts[i]; | |||
out << formatting.parts[i]; | |||
if( i < formatting.indexes.size() ) { | |||
if(formatting.indexes[i]==0) { | |||
std::string const &hkey = formatting.keys[i]; | |||
std::map<std::string,std::string>::const_iterator p; | |||
p = data_helpers_override.find(hkey); | |||
string_key hkey = string_key::unowned(formatting.keys[i]); | |||
std::map<string_key,std::string>::const_iterator p; | |||
p = data_helpers_override.find(string_key::unowned(hkey)); | |||
if(p != data_helpers_override.end()) { | |||
*out << p->second; | |||
out << p->second; | |||
} | |||
else { | |||
p = data_helpers_default.find(hkey); | |||
if(p!=data_helpers_default.end()) | |||
*out << p->second; | |||
out << p->second; | |||
} | |||
} | |||
else { | |||
@@ -129,21 +148,46 @@ namespace cppcms { | |||
if(index >= params_no) { | |||
throw cppcms_error("url_mapper: Index of parameter out of range"); | |||
} | |||
(*params[index])(*out); | |||
(*params[index])(out); | |||
} | |||
} | |||
} | |||
} | |||
void map( string_key const &key, | |||
string_key const &full_url, | |||
filters::streamable const * const *params, | |||
size_t params_no, | |||
std::map<string_key,std::string> const &data_helpers_default, | |||
std::map<string_key,std::string> const &data_helpers_override, | |||
std::ostream &out) const | |||
{ | |||
entry const &formatting = get_entry(key,params_no,full_url); | |||
if(parent) { | |||
std::string url = ss.str(); | |||
stream_it<data,entry> url = | |||
{ | |||
this, | |||
formatting, | |||
params, | |||
params_no, | |||
data_helpers_default, | |||
data_helpers_override | |||
}; | |||
filters::streamable stream_url(url); | |||
filters::streamable const *par_ptr=&stream_url; | |||
parent->mapper().d->map(this_name,full_url,&par_ptr,1,data_helpers_default,data_helpers_override,output); | |||
parent->mapper().d->map(this_name,full_url,&par_ptr,1, data_helpers_default, | |||
data_helpers_override,out); | |||
} | |||
else { | |||
out << root; | |||
write(formatting,params,params_no,data_helpers_default,data_helpers_override,out); | |||
} | |||
} | |||
}; | |||
void url_mapper::assign(std::string const &key,std::string const &url) | |||
@@ -268,8 +312,8 @@ namespace cppcms { | |||
app.mapper().d->this_name = name; | |||
real_assign(name,url,&app); | |||
// Copy all values to root most one | |||
std::map<std::string,std::string> &values = app.mapper().d->helpers; | |||
std::map<std::string,std::string>::const_iterator p; | |||
std::map<string_key,std::string> &values = app.mapper().d->helpers; | |||
std::map<string_key,std::string>::const_iterator p; | |||
for(p=values.begin();p!=values.end();++p) { | |||
set_value(p->first,p->second); | |||
} | |||
@@ -295,7 +339,7 @@ namespace cppcms { | |||
} | |||
url_mapper &url_mapper::get_mapper_for_key(std::string const &key,std::string &real_key,std::vector<std::string> &keywords) | |||
url_mapper &url_mapper::get_mapper_for_key(string_key const &key,string_key &real_key,std::vector<string_key> &keywords) | |||
{ | |||
url_mapper *mapper = this; | |||
size_t pos = 0; | |||
@@ -312,15 +356,16 @@ namespace cppcms { | |||
if(end == std::string::npos) { | |||
size_t separator = key.find(';',pos); | |||
if(separator == std::string::npos) { | |||
real_key = key.substr(pos); | |||
real_key = key.unowned_substr(pos); | |||
} | |||
else { | |||
real_key = key.substr(pos,separator - pos); | |||
keywords.reserve(6); | |||
real_key = key.unowned_substr(pos,separator - pos); | |||
pos = separator + 1; | |||
for(;;){ | |||
end = key.find(',',pos); | |||
size_t size = end - pos; | |||
keywords.push_back(key.substr(pos,size)); | |||
keywords.push_back(key.unowned_substr(pos,size)); | |||
if(end == std::string::npos) | |||
break; | |||
pos = end + 1; | |||
@@ -343,13 +388,13 @@ namespace cppcms { | |||
return *mapper; | |||
} | |||
size_t chunk_size = end - pos; | |||
if(key.compare(pos,chunk_size,".") == 0) | |||
string_key subapp = key.unowned_substr(pos,chunk_size); | |||
if(subapp == ".") | |||
; // Just continue where we are | |||
else if(key.compare(pos,chunk_size,"..")==0) { | |||
else if(subapp == "..") { | |||
mapper = &mapper->parent(); | |||
} | |||
else { | |||
std::string subapp = key.substr(pos,chunk_size); | |||
mapper = &mapper->d->child(subapp,key); | |||
} | |||
pos = end + 1; | |||
@@ -357,17 +402,18 @@ namespace cppcms { | |||
} | |||
void url_mapper::real_map( std::string const &key, | |||
void url_mapper::real_map( char const *ckey, | |||
filters::streamable const * const *params, | |||
size_t params_no, | |||
std::ostream &output) | |||
{ | |||
std::string real_key; | |||
std::vector<std::string> direct; | |||
string_key key=string_key::unowned(ckey); | |||
string_key real_key; | |||
std::vector<string_key> direct; | |||
url_mapper &mp = get_mapper_for_key(key,real_key,direct); | |||
if(params_no < direct.size()) | |||
throw cppcms_error("url_mapper: number of keywords is larger then number of actual parameters"); | |||
std::map<std::string,std::string> mappings; | |||
std::map<string_key,std::string> mappings; | |||
if(direct.size() == 0) { | |||
mp.d->map(real_key,key,params,params_no,topmost().d->helpers,mappings,output); | |||
} | |||
@@ -385,23 +431,86 @@ namespace cppcms { | |||
mp.d->map(real_key,key,params,params_no,topmost().d->helpers,mappings,output); | |||
} | |||
} | |||
void url_mapper::map( std::ostream &out, | |||
std::string const &key) | |||
{ | |||
real_map(key,0,0,out); | |||
map(out,key.c_str()); | |||
} | |||
void url_mapper::map( std::ostream &out, | |||
std::string const &key, | |||
filters::streamable const &p1) | |||
{ | |||
map(out,key.c_str(),p1); | |||
} | |||
void url_mapper::map( std::ostream &out, | |||
std::string const &key, | |||
filters::streamable const &p1, | |||
filters::streamable const &p2) | |||
{ | |||
map(out,key.c_str(),p1,p2); | |||
} | |||
void url_mapper::map( std::ostream &out, | |||
std::string const &key, | |||
filters::streamable const &p1, | |||
filters::streamable const &p2, | |||
filters::streamable const &p3) | |||
{ | |||
map(out,key.c_str(),p1,p2,p3); | |||
} | |||
void url_mapper::map( std::ostream &out, | |||
std::string const &key, | |||
filters::streamable const &p1, | |||
filters::streamable const &p2, | |||
filters::streamable const &p3, | |||
filters::streamable const &p4) | |||
{ | |||
map(out,key.c_str(),p1,p2,p3,p4); | |||
} | |||
void url_mapper::map( std::ostream &out, | |||
std::string const &key, | |||
filters::streamable const &p1, | |||
filters::streamable const &p2, | |||
filters::streamable const &p3, | |||
filters::streamable const &p4, | |||
filters::streamable const &p5) | |||
{ | |||
map(out,key.c_str(),p1,p2,p3,p4,p5); | |||
} | |||
void url_mapper::map( std::ostream &out, | |||
std::string const &key, | |||
filters::streamable const &p1, | |||
filters::streamable const &p2, | |||
filters::streamable const &p3, | |||
filters::streamable const &p4, | |||
filters::streamable const &p5, | |||
filters::streamable const &p6) | |||
{ | |||
map(out,key.c_str(),p1,p2,p3,p4,p5,p6); | |||
} | |||
void url_mapper::map( std::ostream &out, | |||
char const *key) | |||
{ | |||
real_map(key,0,0,out); | |||
} | |||
void url_mapper::map( std::ostream &out, | |||
char const *key, | |||
filters::streamable const &p1) | |||
{ | |||
filters::streamable const *params[1]= { &p1 }; | |||
real_map(key,params,1,out); | |||
} | |||
void url_mapper::map( std::ostream &out, | |||
std::string const &key, | |||
char const *key, | |||
filters::streamable const &p1, | |||
filters::streamable const &p2) | |||
{ | |||
@@ -410,7 +519,7 @@ namespace cppcms { | |||
} | |||
void url_mapper::map( std::ostream &out, | |||
std::string const &key, | |||
char const *key, | |||
filters::streamable const &p1, | |||
filters::streamable const &p2, | |||
filters::streamable const &p3) | |||
@@ -420,7 +529,7 @@ namespace cppcms { | |||
} | |||
void url_mapper::map( std::ostream &out, | |||
std::string const &key, | |||
char const *key, | |||
filters::streamable const &p1, | |||
filters::streamable const &p2, | |||
filters::streamable const &p3, | |||
@@ -431,7 +540,7 @@ namespace cppcms { | |||
} | |||
void url_mapper::map( std::ostream &out, | |||
std::string const &key, | |||
char const *key, | |||
filters::streamable const &p1, | |||
filters::streamable const &p2, | |||
filters::streamable const &p3, | |||
@@ -443,7 +552,7 @@ namespace cppcms { | |||
} | |||
void url_mapper::map( std::ostream &out, | |||
std::string const &key, | |||
char const *key, | |||
filters::streamable const &p1, | |||
filters::streamable const &p2, | |||
filters::streamable const &p3, | |||
@@ -20,6 +20,7 @@ | |||
#include <cppcms/util.h> | |||
#include "http_protocol.h" | |||
#include <stdio.h> | |||
#include <iterator> | |||
#include "md5.h" | |||
namespace cppcms { | |||
@@ -43,18 +44,31 @@ std::string escape(std::string const &s) | |||
return content; | |||
} | |||
std::string urlencode(std::string const &s) | |||
void escape(char const *begin,char const *end,std::ostream &output) | |||
{ | |||
std::string content; | |||
unsigned i,len=s.size(); | |||
content.reserve(3*len); | |||
for(i=0;i<len;i++){ | |||
char c=s[i]; | |||
while(begin!=end) { | |||
char c=*begin++; | |||
switch(c){ | |||
case '<': output << "<"; break; | |||
case '>': output << ">"; break; | |||
case '&': output << "&"; break; | |||
case '\"': output<<"""; break; | |||
default: output << c; | |||
} | |||
} | |||
} | |||
template<typename Iterator> | |||
void urlencode_impl(char const *b,char const *e,Iterator out) | |||
{ | |||
while(b!=e){ | |||
char c=*b++; | |||
if( ('a'<=c && c<='z') | |||
|| ('A'<=c && c<='Z') | |||
|| ('0'<=c && c<='9')) | |||
{ | |||
content+=c; | |||
*out++ = c; | |||
} | |||
else { | |||
switch(c) { | |||
@@ -62,20 +76,33 @@ std::string urlencode(std::string const &s) | |||
case '_': | |||
case '.': | |||
case '~': | |||
content+=c; | |||
*out++ = c; | |||
break; | |||
default: | |||
{ | |||
static char const hex[]="0123456789abcdef"; | |||
unsigned char uc = c; | |||
content += '%'; | |||
content += hex[(uc >> 4) & 0xF]; | |||
content += hex[ uc & 0xF]; | |||
*out++ = '%'; | |||
*out++ = hex[(uc >> 4) & 0xF]; | |||
*out++ = hex[ uc & 0xF]; | |||
} | |||
}; | |||
} | |||
}; | |||
} | |||
void urlencode(char const *b,char const *e,std::ostream &out) | |||
{ | |||
std::ostream_iterator<char> it(out); | |||
urlencode_impl(b,e,it); | |||
} | |||
std::string urlencode(std::string const &s) | |||
{ | |||
std::string content; | |||
content.reserve(3*s.size()); | |||
std::back_insert_iterator<std::string> out(content); | |||
urlencode_impl(s.c_str(),s.c_str()+s.size(),out); | |||
return content; | |||
} | |||