redsnow 0.2.1 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +2 -0
- data/ext/snowcrash/bin/snowcrash +0 -0
- data/ext/snowcrash/snowcrash.xcworkspace/contents.xcworkspacedata +10 -0
- data/ext/snowcrash/src/ActionParser.h +35 -33
- data/ext/snowcrash/src/AssetParser.h +17 -17
- data/ext/snowcrash/src/Blueprint.h +101 -66
- data/ext/snowcrash/src/BlueprintParser.h +219 -10
- data/ext/snowcrash/src/BlueprintSourcemap.h +1 -1
- data/ext/snowcrash/src/BlueprintUtility.h +14 -14
- data/ext/snowcrash/src/CBlueprint.cc +29 -10
- data/ext/snowcrash/src/CBlueprint.h +19 -3
- data/ext/snowcrash/src/CBlueprintSourcemap.cc +20 -10
- data/ext/snowcrash/src/CBlueprintSourcemap.h +12 -3
- data/ext/snowcrash/src/CodeBlockUtility.h +25 -25
- data/ext/snowcrash/src/HTTP.cc +3 -0
- data/ext/snowcrash/src/HTTP.h +9 -6
- data/ext/snowcrash/src/HeadersParser.h +34 -14
- data/ext/snowcrash/src/ParameterParser.h +21 -21
- data/ext/snowcrash/src/ParametersParser.h +6 -5
- data/ext/snowcrash/src/PayloadParser.h +174 -129
- data/ext/snowcrash/src/RegexMatch.h +3 -3
- data/ext/snowcrash/src/ResourceGroupParser.h +5 -4
- data/ext/snowcrash/src/ResourceParser.h +30 -26
- data/ext/snowcrash/src/Section.cc +6 -6
- data/ext/snowcrash/src/Section.h +2 -2
- data/ext/snowcrash/src/SectionParser.h +41 -41
- data/ext/snowcrash/src/SectionParserData.h +10 -10
- data/ext/snowcrash/src/SectionProcessor.h +70 -30
- data/ext/snowcrash/src/Serialize.h +3 -3
- data/ext/snowcrash/src/SerializeJSON.cc +124 -96
- data/ext/snowcrash/src/SerializeJSON.h +1 -1
- data/ext/snowcrash/src/SerializeYAML.cc +71 -53
- data/ext/snowcrash/src/SerializeYAML.h +1 -1
- data/ext/snowcrash/src/Signature.cc +2 -2
- data/ext/snowcrash/src/Signature.h +1 -1
- data/ext/snowcrash/src/SourceAnnotation.h +23 -23
- data/ext/snowcrash/src/StringUtility.h +71 -9
- data/ext/snowcrash/src/SymbolTable.h +17 -17
- data/ext/snowcrash/src/UriTemplateParser.cc +5 -5
- data/ext/snowcrash/src/UriTemplateParser.h +9 -9
- data/ext/snowcrash/src/ValuesParser.h +2 -2
- data/ext/snowcrash/src/Version.h +1 -1
- data/ext/snowcrash/src/csnowcrash.cc +10 -8
- data/ext/snowcrash/src/snowcrash.cc +9 -9
- data/ext/snowcrash/src/snowcrash.h +6 -8
- data/ext/snowcrash/src/snowcrash/snowcrash.cc +14 -14
- data/ext/snowcrash/src/win/RegexMatch.cc +7 -7
- data/ext/snowcrash/tools/gyp/pylib/gyp/__init__.pyc +0 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/common.pyc +0 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/generator/__init__.pyc +0 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/generator/make.pyc +0 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/generator/xcode.pyc +0 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/input.pyc +0 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/xcode_emulation.pyc +0 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/xcodeproj_file.pyc +0 -0
- data/ext/snowcrash/tools/homebrew/snowcrash.rb +1 -1
- data/lib/redsnow/binding.rb +8 -2
- data/lib/redsnow/blueprint.rb +4 -3
- data/lib/redsnow/sourcemap.rb +6 -4
- data/lib/redsnow/version.rb +1 -1
- metadata +4 -17
@@ -272,16 +272,6 @@ SC_API const sc_source_map_t* sc_sm_payload_name(const sc_sm_payload_t* handle)
|
|
272
272
|
return AS_CTYPE(sc_source_map_t, &p->name.sourceMap);
|
273
273
|
}
|
274
274
|
|
275
|
-
/** TODO: Need to change this to use the "Reference" data structure */
|
276
|
-
SC_API const sc_source_map_t* sc_sm_payload_symbol(const sc_sm_payload_t* handle)
|
277
|
-
{
|
278
|
-
const snowcrash::SourceMap<snowcrash::Payload>* p = AS_CTYPE(snowcrash::SourceMap<snowcrash::Payload>, handle);
|
279
|
-
if (!p)
|
280
|
-
return NULL;
|
281
|
-
|
282
|
-
return AS_CTYPE(sc_source_map_t, &p->symbol.sourceMap);
|
283
|
-
}
|
284
|
-
|
285
275
|
SC_API const sc_source_map_t* sc_sm_payload_description(const sc_sm_payload_t* handle)
|
286
276
|
{
|
287
277
|
const snowcrash::SourceMap<snowcrash::Payload>* p = AS_CTYPE(snowcrash::SourceMap<snowcrash::Payload>, handle);
|
@@ -311,6 +301,26 @@ SC_API const sc_source_map_t* sc_sm_payload_schema(const sc_sm_payload_t* handle
|
|
311
301
|
|
312
302
|
/*----------------------------------------------------------------------*/
|
313
303
|
|
304
|
+
SC_API const sc_sm_reference_t* sc_sm_reference_handle(const sc_sm_payload_t* handle)
|
305
|
+
{
|
306
|
+
const snowcrash::SourceMap<snowcrash::Payload>* p = AS_CTYPE(snowcrash::SourceMap<snowcrash::Payload>, handle);
|
307
|
+
if(!p)
|
308
|
+
return NULL;
|
309
|
+
|
310
|
+
return AS_CTYPE(sc_sm_reference_t, &p->reference);
|
311
|
+
}
|
312
|
+
|
313
|
+
SC_API const sc_source_map_t* sc_sm_reference(const sc_sm_reference_t* handle)
|
314
|
+
{
|
315
|
+
const snowcrash::SourceMap<snowcrash::Reference>* p = AS_CTYPE(snowcrash::SourceMap<snowcrash::Reference>, handle);
|
316
|
+
if (!p)
|
317
|
+
return NULL;
|
318
|
+
|
319
|
+
return AS_CTYPE(sc_source_map_t, &p->sourceMap);
|
320
|
+
}
|
321
|
+
|
322
|
+
/*----------------------------------------------------------------------*/
|
323
|
+
|
314
324
|
SC_API const sc_sm_parameter_collection_t* sc_sm_parameter_collection_handle_payload(const sc_sm_payload_t* handle)
|
315
325
|
{
|
316
326
|
const snowcrash::SourceMap<snowcrash::Payload>* p = AS_CTYPE(snowcrash::SourceMap<snowcrash::Payload>, handle);
|
@@ -53,6 +53,10 @@ extern "C" {
|
|
53
53
|
struct sc_sm_resource_model_s;
|
54
54
|
typedef struct sc_sm_resource_model_s sc_sm_resource_model_t;
|
55
55
|
|
56
|
+
/** Class Reference source map wrapper */
|
57
|
+
struct sc_sm_reference_s;
|
58
|
+
typedef struct sc_sm_reference_s sc_sm_reference_t;
|
59
|
+
|
56
60
|
/** Array Payload Collection source map wrapper */
|
57
61
|
struct sc_sm_payload_collection_s;
|
58
62
|
typedef struct sc_sm_payload_collection_s sc_sm_payload_collection_t;
|
@@ -205,9 +209,6 @@ extern "C" {
|
|
205
209
|
/** \returns Payload name source map */
|
206
210
|
SC_API const sc_source_map_t* sc_sm_payload_name(const sc_sm_payload_t* handle);
|
207
211
|
|
208
|
-
/** \returns Payload symbol name source map */
|
209
|
-
SC_API const sc_source_map_t* sc_sm_payload_symbol(const sc_sm_payload_t* handle);
|
210
|
-
|
211
212
|
/** \returns Payload description source map */
|
212
213
|
SC_API const sc_source_map_t* sc_sm_payload_description(const sc_sm_payload_t* handle);
|
213
214
|
|
@@ -219,6 +220,14 @@ extern "C" {
|
|
219
220
|
|
220
221
|
/*----------------------------------------------------------------------*/
|
221
222
|
|
223
|
+
/** \returns Reference source map handle */
|
224
|
+
SC_API const sc_sm_reference_t* sc_sm_reference_handle(const sc_sm_payload_t* handle);
|
225
|
+
|
226
|
+
/** \returns Reference identifier source map */
|
227
|
+
SC_API const sc_source_map_t* sc_sm_reference(const sc_sm_reference_t* handle);
|
228
|
+
|
229
|
+
/*----------------------------------------------------------------------*/
|
230
|
+
|
222
231
|
/** \returns Parameter Collection source map array handle from Payload source map */
|
223
232
|
SC_API const sc_sm_parameter_collection_t* sc_sm_parameter_collection_handle_payload(const sc_sm_payload_t* handle);
|
224
233
|
|
@@ -14,9 +14,9 @@
|
|
14
14
|
#include "StringUtility.h"
|
15
15
|
|
16
16
|
namespace snowcrash {
|
17
|
-
|
17
|
+
|
18
18
|
struct CodeBlockUtility {
|
19
|
-
|
19
|
+
|
20
20
|
/**
|
21
21
|
* \brief Expected indentation level of a code block.
|
22
22
|
*
|
@@ -30,21 +30,21 @@ namespace snowcrash {
|
|
30
30
|
type == ResourceGroupSectionType ||
|
31
31
|
type == ResourceSectionType ||
|
32
32
|
type == ActionSectionType) {
|
33
|
-
|
33
|
+
|
34
34
|
return 1;
|
35
35
|
}
|
36
36
|
else if (type == RequestBodySectionType ||
|
37
37
|
type == ResponseBodySectionType ||
|
38
38
|
type == ModelBodySectionType) {
|
39
|
-
|
39
|
+
|
40
40
|
return 2;
|
41
41
|
}
|
42
42
|
else {
|
43
|
-
|
43
|
+
|
44
44
|
return 3;
|
45
45
|
}
|
46
46
|
}
|
47
|
-
|
47
|
+
|
48
48
|
/**
|
49
49
|
* \brief Retrieve the textual content of a Markdown node as if it was a code block.
|
50
50
|
* \param pd Parser status
|
@@ -57,14 +57,14 @@ namespace snowcrash {
|
|
57
57
|
mdp::ByteBuffer& content) {
|
58
58
|
|
59
59
|
checkPossibleReference(node, pd, report);
|
60
|
-
|
60
|
+
|
61
61
|
if (node->type == mdp::CodeMarkdownNodeType) {
|
62
62
|
content += node->text;
|
63
63
|
|
64
64
|
checkExcessiveIndentation(node, pd, report);
|
65
65
|
return;
|
66
66
|
}
|
67
|
-
|
67
|
+
|
68
68
|
// Other blocks, process & warn
|
69
69
|
content += mdp::MapBytesRangeSet(node->sourceMap, pd.sourceData);
|
70
70
|
|
@@ -79,25 +79,25 @@ namespace snowcrash {
|
|
79
79
|
|
80
80
|
ss << " is expected to be a pre-formatted code block, every of its line indented by exactly ";
|
81
81
|
ss << level * 4 << " spaces or " << level << " tabs";
|
82
|
-
|
82
|
+
|
83
83
|
mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(node->sourceMap, pd.sourceData);
|
84
84
|
report.warnings.push_back(Warning(ss.str(),
|
85
85
|
IndentationWarning,
|
86
86
|
sourceMap));
|
87
87
|
}
|
88
|
-
|
88
|
+
|
89
89
|
/** \brief Retrieve the textual content of a signature markdown */
|
90
90
|
static void signatureContentAsCodeBlock(const MarkdownNodeIterator& node,
|
91
91
|
const SectionParserData& pd,
|
92
92
|
Report& report,
|
93
93
|
mdp::ByteBuffer& content) {
|
94
|
-
|
94
|
+
|
95
95
|
mdp::ByteBuffer remainingContent;
|
96
96
|
GetFirstLine(node->text, remainingContent);
|
97
|
-
|
97
|
+
|
98
98
|
if (remainingContent.empty())
|
99
99
|
return;
|
100
|
-
|
100
|
+
|
101
101
|
content += remainingContent;
|
102
102
|
content += "\n";
|
103
103
|
|
@@ -114,13 +114,13 @@ namespace snowcrash {
|
|
114
114
|
ss << " is expected to be a pre-formatted code block, separate it by a newline and ";
|
115
115
|
ss << "indent every of its line by ";
|
116
116
|
ss << level * 4 << " spaces or " << level << " tabs";
|
117
|
-
|
117
|
+
|
118
118
|
mdp::CharactersRangeSet sourceMap = mdp::BytesRangeSetToCharactersRangeSet(node->sourceMap, pd.sourceData);
|
119
119
|
report.warnings.push_back(Warning(ss.str(),
|
120
120
|
IndentationWarning,
|
121
121
|
sourceMap));
|
122
122
|
}
|
123
|
-
|
123
|
+
|
124
124
|
/**
|
125
125
|
* \brief Check for potential excessive indentation of a list section
|
126
126
|
* \return True if code block contains a recognized list section, false otherwise.
|
@@ -128,7 +128,7 @@ namespace snowcrash {
|
|
128
128
|
static bool checkExcessiveIndentation(const MarkdownNodeIterator& node,
|
129
129
|
const SectionParserData& pd,
|
130
130
|
Report& report) {
|
131
|
-
|
131
|
+
|
132
132
|
// Check for possible superfluous indentation of a recognized list items.
|
133
133
|
mdp::ByteBuffer r;
|
134
134
|
mdp::ByteBuffer line = GetFirstLine(node->text, r);
|
@@ -138,11 +138,11 @@ namespace snowcrash {
|
|
138
138
|
if (line.empty() ||
|
139
139
|
(line[0] != '-' && line[0] != '+' && line[0] != '*'))
|
140
140
|
return false;
|
141
|
-
|
141
|
+
|
142
142
|
// Skip leading Markdown list item mark
|
143
143
|
std::string signature = line.substr(1, std::string::npos);
|
144
144
|
TrimStringStart(signature);
|
145
|
-
|
145
|
+
|
146
146
|
SectionType type = RecognizeCodeBlockFirstLine(signature);
|
147
147
|
|
148
148
|
if (type != UndefinedSectionType) {
|
@@ -172,7 +172,7 @@ namespace snowcrash {
|
|
172
172
|
IndentationWarning,
|
173
173
|
sourceMap));
|
174
174
|
}
|
175
|
-
|
175
|
+
|
176
176
|
return false;
|
177
177
|
}
|
178
178
|
|
@@ -184,15 +184,15 @@ namespace snowcrash {
|
|
184
184
|
*/
|
185
185
|
static bool keyValueFromLine(const mdp::ByteBuffer& line,
|
186
186
|
KeyValuePair& keyValuePair) {
|
187
|
-
|
187
|
+
|
188
188
|
std::vector<std::string> rawMetadata = SplitOnFirst(line, ':');
|
189
189
|
if (rawMetadata.size() != 2)
|
190
190
|
return false;
|
191
|
-
|
191
|
+
|
192
192
|
keyValuePair = std::make_pair(rawMetadata[0], rawMetadata[1]);
|
193
193
|
TrimString(keyValuePair.first);
|
194
194
|
TrimString(keyValuePair.second);
|
195
|
-
|
195
|
+
|
196
196
|
return (!keyValuePair.first.empty() && !keyValuePair.second.empty());
|
197
197
|
}
|
198
198
|
|
@@ -218,14 +218,14 @@ namespace snowcrash {
|
|
218
218
|
|
219
219
|
TwoNewLines(asset);
|
220
220
|
out += asset;
|
221
|
-
|
221
|
+
|
222
222
|
size_t level = CodeBlockUtility::codeBlockIndentationLevel(sectionType);
|
223
223
|
|
224
224
|
if (node->type == mdp::CodeMarkdownNodeType)
|
225
225
|
level--; // Deduct one level for a code block
|
226
226
|
|
227
227
|
checkPossibleReference(node, pd, report);
|
228
|
-
|
228
|
+
|
229
229
|
if (level) {
|
230
230
|
// WARN: Dangling asset
|
231
231
|
std::stringstream ss;
|
@@ -250,7 +250,7 @@ namespace snowcrash {
|
|
250
250
|
Report& report) {
|
251
251
|
|
252
252
|
mdp::ByteBuffer source = node->text;
|
253
|
-
|
253
|
+
Identifier symbol;
|
254
254
|
|
255
255
|
TrimString(source);
|
256
256
|
|
data/ext/snowcrash/src/HTTP.cc
CHANGED
@@ -15,6 +15,9 @@ const std::string HTTPHeaderName::ContentLength = "Content-Length";
|
|
15
15
|
const std::string HTTPHeaderName::ContentType = "Content-Type";
|
16
16
|
const std::string HTTPHeaderName::TransferEncoding = "Transfer-Encoding";
|
17
17
|
|
18
|
+
const std::string HTTPHeaderName::SetCookie = "Set-Cookie";
|
19
|
+
const std::string HTTPHeaderName::Link = "Link";
|
20
|
+
|
18
21
|
const std::string HTTPMethodName::Head = "HEAD";
|
19
22
|
const std::string HTTPMethodName::Connect = "CONNECT";
|
20
23
|
|
data/ext/snowcrash/src/HTTP.h
CHANGED
@@ -13,7 +13,7 @@
|
|
13
13
|
#include "Blueprint.h"
|
14
14
|
|
15
15
|
/**
|
16
|
-
* \brief HTTP Methods
|
16
|
+
* \brief HTTP Methods
|
17
17
|
*
|
18
18
|
* Technical note: Using preprocessor macro instead of strict
|
19
19
|
* defined type due to C++98 string concatenation limitations.
|
@@ -21,7 +21,7 @@
|
|
21
21
|
*/
|
22
22
|
#define HTTP_REQUEST_METHOD "(GET|POST|PUT|DELETE|OPTIONS|PATCH|PROPPATCH|LOCK|UNLOCK|COPY|MOVE|MKCOL|HEAD|LINK|UNLINK|CONNECT)"
|
23
23
|
|
24
|
-
/**
|
24
|
+
/**
|
25
25
|
* \brief URI Template.
|
26
26
|
*
|
27
27
|
* See previous technical note (using macro).
|
@@ -29,7 +29,7 @@
|
|
29
29
|
#define URI_TEMPLATE "(/.*)"
|
30
30
|
|
31
31
|
namespace snowcrash {
|
32
|
-
|
32
|
+
|
33
33
|
/**
|
34
34
|
* Selected HTTP Header names.
|
35
35
|
*/
|
@@ -38,6 +38,9 @@ namespace snowcrash {
|
|
38
38
|
static const std::string ContentLength;
|
39
39
|
static const std::string ContentType;
|
40
40
|
static const std::string TransferEncoding;
|
41
|
+
|
42
|
+
static const std::string SetCookie;
|
43
|
+
static const std::string Link;
|
41
44
|
};
|
42
45
|
|
43
46
|
/**
|
@@ -57,9 +60,9 @@ namespace snowcrash {
|
|
57
60
|
* Traits of a HTTP response.
|
58
61
|
*/
|
59
62
|
struct HTTPResponseTraits {
|
60
|
-
|
63
|
+
|
61
64
|
bool allowBody; /// < Response body is allowed.
|
62
|
-
|
65
|
+
|
63
66
|
HTTPResponseTraits() : allowBody(true) {}
|
64
67
|
};
|
65
68
|
|
@@ -86,7 +89,7 @@ namespace snowcrash {
|
|
86
89
|
HTTPStatusCode code;
|
87
90
|
StatusCodeTraits() : code(0) {}
|
88
91
|
};
|
89
|
-
|
92
|
+
|
90
93
|
/**
|
91
94
|
* \brief Retrieve response traits for given HTTP method.
|
92
95
|
* \param method HTTP method to retrieve traits for.
|
@@ -22,18 +22,18 @@ namespace snowcrash {
|
|
22
22
|
|
23
23
|
/** Header Iterator in its containment group */
|
24
24
|
typedef Collection<Header>::const_iterator HeaderIterator;
|
25
|
-
|
25
|
+
|
26
26
|
/**
|
27
27
|
* Headers Section Processor
|
28
28
|
*/
|
29
29
|
template<>
|
30
30
|
struct SectionProcessor<Headers> : public SectionProcessorBase<Headers> {
|
31
|
-
|
31
|
+
|
32
32
|
static MarkdownNodeIterator processSignature(const MarkdownNodeIterator& node,
|
33
33
|
const MarkdownNodes& siblings,
|
34
34
|
SectionParserData& pd,
|
35
35
|
SectionLayout& layout,
|
36
|
-
|
36
|
+
const ParseResultRef<Headers>& out) {
|
37
37
|
|
38
38
|
mdp::ByteBuffer content;
|
39
39
|
CodeBlockUtility::signatureContentAsCodeBlock(node, pd, out.report, content);
|
@@ -42,11 +42,11 @@ namespace snowcrash {
|
|
42
42
|
|
43
43
|
return ++MarkdownNodeIterator(node);
|
44
44
|
}
|
45
|
-
|
45
|
+
|
46
46
|
static MarkdownNodeIterator processDescription(const MarkdownNodeIterator& node,
|
47
47
|
const MarkdownNodes& siblings,
|
48
48
|
SectionParserData& pd,
|
49
|
-
|
49
|
+
const ParseResultRef<Headers>& out) {
|
50
50
|
|
51
51
|
return node;
|
52
52
|
}
|
@@ -54,7 +54,7 @@ namespace snowcrash {
|
|
54
54
|
static MarkdownNodeIterator processContent(const MarkdownNodeIterator& node,
|
55
55
|
const MarkdownNodes& siblings,
|
56
56
|
SectionParserData& pd,
|
57
|
-
|
57
|
+
const ParseResultRef<Headers>& out) {
|
58
58
|
|
59
59
|
mdp::ByteBuffer content;
|
60
60
|
CodeBlockUtility::contentAsCodeBlock(node, pd, out.report, content);
|
@@ -63,18 +63,18 @@ namespace snowcrash {
|
|
63
63
|
|
64
64
|
return ++MarkdownNodeIterator(node);
|
65
65
|
}
|
66
|
-
|
66
|
+
|
67
67
|
static bool isDescriptionNode(const MarkdownNodeIterator& node,
|
68
68
|
SectionType sectionType) {
|
69
69
|
return false;
|
70
70
|
}
|
71
|
-
|
71
|
+
|
72
72
|
static bool isContentNode(const MarkdownNodeIterator& node,
|
73
73
|
SectionType sectionType) {
|
74
74
|
|
75
75
|
return (SectionKeywordSignature(node) == UndefinedSectionType);
|
76
76
|
}
|
77
|
-
|
77
|
+
|
78
78
|
static SectionType sectionType(const MarkdownNodeIterator& node) {
|
79
79
|
|
80
80
|
if (node->type == mdp::ListItemMarkdownNodeType
|
@@ -83,7 +83,7 @@ namespace snowcrash {
|
|
83
83
|
mdp::ByteBuffer subject = node->children().front().text;
|
84
84
|
mdp::ByteBuffer signature;
|
85
85
|
mdp::ByteBuffer remainingContent;
|
86
|
-
|
86
|
+
|
87
87
|
signature = GetFirstLine(subject, remainingContent);
|
88
88
|
TrimString(signature);
|
89
89
|
|
@@ -96,7 +96,7 @@ namespace snowcrash {
|
|
96
96
|
|
97
97
|
static void finalize(const MarkdownNodeIterator& node,
|
98
98
|
SectionParserData& pd,
|
99
|
-
|
99
|
+
const ParseResultRef<Headers>& out) {
|
100
100
|
|
101
101
|
if (out.node.empty()) {
|
102
102
|
|
@@ -112,7 +112,7 @@ namespace snowcrash {
|
|
112
112
|
static void headersFromContent(const MarkdownNodeIterator& node,
|
113
113
|
const mdp::ByteBuffer& content,
|
114
114
|
SectionParserData& pd,
|
115
|
-
|
115
|
+
const ParseResultRef<Headers>& out) {
|
116
116
|
|
117
117
|
std::vector<std::string> lines = Split(content, '\n');
|
118
118
|
|
@@ -127,7 +127,7 @@ namespace snowcrash {
|
|
127
127
|
Header header;
|
128
128
|
|
129
129
|
if (CodeBlockUtility::keyValueFromLine(*line, header)) {
|
130
|
-
if (findHeader(out.node, header) != out.node.end()) {
|
130
|
+
if (findHeader(out.node, header) != out.node.end() && !isAllowedMultipleDefinition(header)) {
|
131
131
|
// WARN: duplicate header on this level
|
132
132
|
std::stringstream ss;
|
133
133
|
|
@@ -228,7 +228,27 @@ namespace snowcrash {
|
|
228
228
|
|
229
229
|
return std::find_if(headers.begin(),
|
230
230
|
headers.end(),
|
231
|
-
std::bind2nd(MatchFirsts<Header>(), header));
|
231
|
+
std::bind2nd(MatchFirsts<Header, IEqual<typename Header::first_type> >(), header));
|
232
|
+
}
|
233
|
+
|
234
|
+
typedef std::vector<std::string> HeadersKeyCollection;
|
235
|
+
/** Get collection of allowed keywords - workarround due to C++98 restriction - static initialization of vector */
|
236
|
+
static const HeadersKeyCollection& getAllowedMultipleDefinitions() {
|
237
|
+
static std::string keys[] = {
|
238
|
+
HTTPHeaderName::SetCookie,
|
239
|
+
HTTPHeaderName::Link,
|
240
|
+
};
|
241
|
+
|
242
|
+
static const HeadersKeyCollection allowedMultipleDefinitions(keys, keys + (sizeof(keys)/sizeof(keys[0])));
|
243
|
+
return allowedMultipleDefinitions;
|
244
|
+
}
|
245
|
+
|
246
|
+
/** Check if Header name has allowed multiple definitions */
|
247
|
+
static bool isAllowedMultipleDefinition(const Header& header) {
|
248
|
+
const HeadersKeyCollection& keys = getAllowedMultipleDefinitions();
|
249
|
+
return std::find_if(keys.begin(),
|
250
|
+
keys.end(),
|
251
|
+
std::bind1st(MatchFirstWith<Header, std::string, IEqual<std::string> >(), header)) != keys.end();
|
232
252
|
}
|
233
253
|
};
|
234
254
|
|