redsnow 0.0.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +34 -0
- data/.gitmodules +3 -0
- data/.travis.yml +20 -0
- data/CHANGELOG.md +4 -0
- data/Gemfile +4 -0
- data/LICENSE +21 -0
- data/README.md +62 -0
- data/Rakefile +36 -0
- data/Vagrantfile +20 -0
- data/ext/snowcrash/Makefile +64 -0
- data/ext/snowcrash/Vagrantfile +20 -0
- data/ext/snowcrash/bin/snowcrash +0 -0
- data/ext/snowcrash/common.gypi +163 -0
- data/ext/snowcrash/config.gypi +10 -0
- data/ext/snowcrash/config.mk +5 -0
- data/ext/snowcrash/configure +213 -0
- data/ext/snowcrash/provisioning.sh +15 -0
- data/ext/snowcrash/snowcrash.gyp +141 -0
- data/ext/snowcrash/src/ActionParser.h +503 -0
- data/ext/snowcrash/src/AssetParser.h +215 -0
- data/ext/snowcrash/src/BlockUtility.h +186 -0
- data/ext/snowcrash/src/Blueprint.h +283 -0
- data/ext/snowcrash/src/BlueprintParser.h +347 -0
- data/ext/snowcrash/src/BlueprintParserCore.h +190 -0
- data/ext/snowcrash/src/BlueprintSection.h +140 -0
- data/ext/snowcrash/src/BlueprintUtility.h +126 -0
- data/ext/snowcrash/src/CBlueprint.cc +600 -0
- data/ext/snowcrash/src/CBlueprint.h +354 -0
- data/ext/snowcrash/src/CSourceAnnotation.cc +140 -0
- data/ext/snowcrash/src/CSourceAnnotation.h +106 -0
- data/ext/snowcrash/src/CodeBlockUtility.h +189 -0
- data/ext/snowcrash/src/DescriptionSectionUtility.h +156 -0
- data/ext/snowcrash/src/HTTP.cc +46 -0
- data/ext/snowcrash/src/HTTP.h +105 -0
- data/ext/snowcrash/src/HeaderParser.h +289 -0
- data/ext/snowcrash/src/ListBlockUtility.h +273 -0
- data/ext/snowcrash/src/ListUtility.h +95 -0
- data/ext/snowcrash/src/MarkdownBlock.cc +176 -0
- data/ext/snowcrash/src/MarkdownBlock.h +93 -0
- data/ext/snowcrash/src/MarkdownParser.cc +266 -0
- data/ext/snowcrash/src/MarkdownParser.h +88 -0
- data/ext/snowcrash/src/ParameterDefinitonParser.h +570 -0
- data/ext/snowcrash/src/ParametersParser.h +252 -0
- data/ext/snowcrash/src/Parser.cc +71 -0
- data/ext/snowcrash/src/Parser.h +29 -0
- data/ext/snowcrash/src/ParserCore.cc +120 -0
- data/ext/snowcrash/src/ParserCore.h +82 -0
- data/ext/snowcrash/src/PayloadParser.h +672 -0
- data/ext/snowcrash/src/Platform.h +54 -0
- data/ext/snowcrash/src/RegexMatch.h +32 -0
- data/ext/snowcrash/src/ResourceGroupParser.h +195 -0
- data/ext/snowcrash/src/ResourceParser.h +584 -0
- data/ext/snowcrash/src/SectionUtility.h +142 -0
- data/ext/snowcrash/src/Serialize.cc +52 -0
- data/ext/snowcrash/src/Serialize.h +69 -0
- data/ext/snowcrash/src/SerializeJSON.cc +601 -0
- data/ext/snowcrash/src/SerializeJSON.h +21 -0
- data/ext/snowcrash/src/SerializeYAML.cc +336 -0
- data/ext/snowcrash/src/SerializeYAML.h +21 -0
- data/ext/snowcrash/src/SourceAnnotation.h +177 -0
- data/ext/snowcrash/src/StringUtility.h +109 -0
- data/ext/snowcrash/src/SymbolTable.h +83 -0
- data/ext/snowcrash/src/UriTemplateParser.cc +195 -0
- data/ext/snowcrash/src/UriTemplateParser.h +243 -0
- data/ext/snowcrash/src/Version.h +39 -0
- data/ext/snowcrash/src/csnowcrash.cc +23 -0
- data/ext/snowcrash/src/csnowcrash.h +38 -0
- data/ext/snowcrash/src/posix/RegexMatch.cc +99 -0
- data/ext/snowcrash/src/snowcrash.cc +18 -0
- data/ext/snowcrash/src/snowcrash.h +41 -0
- data/ext/snowcrash/src/snowcrash/snowcrash.cc +170 -0
- data/ext/snowcrash/src/win/RegexMatch.cc +78 -0
- data/ext/snowcrash/sundown/CONTRIBUTING.md +10 -0
- data/ext/snowcrash/sundown/Makefile +83 -0
- data/ext/snowcrash/sundown/Makefile.win +33 -0
- data/ext/snowcrash/sundown/examples/smartypants.c +72 -0
- data/ext/snowcrash/sundown/examples/sundown.c +80 -0
- data/ext/snowcrash/sundown/html/houdini.h +37 -0
- data/ext/snowcrash/sundown/html/houdini_href_e.c +108 -0
- data/ext/snowcrash/sundown/html/houdini_html_e.c +84 -0
- data/ext/snowcrash/sundown/html/html.c +647 -0
- data/ext/snowcrash/sundown/html/html.h +77 -0
- data/ext/snowcrash/sundown/html/html_smartypants.c +389 -0
- data/ext/snowcrash/sundown/html_block_names.txt +25 -0
- data/ext/snowcrash/sundown/src/autolink.c +297 -0
- data/ext/snowcrash/sundown/src/autolink.h +51 -0
- data/ext/snowcrash/sundown/src/buffer.c +225 -0
- data/ext/snowcrash/sundown/src/buffer.h +96 -0
- data/ext/snowcrash/sundown/src/html_blocks.h +206 -0
- data/ext/snowcrash/sundown/src/markdown.c +2701 -0
- data/ext/snowcrash/sundown/src/markdown.h +147 -0
- data/ext/snowcrash/sundown/src/src_map.c +200 -0
- data/ext/snowcrash/sundown/src/src_map.h +58 -0
- data/ext/snowcrash/sundown/src/stack.c +81 -0
- data/ext/snowcrash/sundown/src/stack.h +29 -0
- data/ext/snowcrash/sundown/sundown.def +20 -0
- data/ext/snowcrash/tools/gyp/AUTHORS +11 -0
- data/ext/snowcrash/tools/gyp/DEPS +24 -0
- data/ext/snowcrash/tools/gyp/OWNERS +1 -0
- data/ext/snowcrash/tools/gyp/PRESUBMIT.py +120 -0
- data/ext/snowcrash/tools/gyp/buildbot/buildbot_run.py +190 -0
- data/ext/snowcrash/tools/gyp/codereview.settings +10 -0
- data/ext/snowcrash/tools/gyp/data/win/large-pdb-shim.cc +12 -0
- data/ext/snowcrash/tools/gyp/gyp +8 -0
- data/ext/snowcrash/tools/gyp/gyp.bat +5 -0
- data/ext/snowcrash/tools/gyp/gyp_main.py +18 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/MSVSNew.py +340 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/MSVSProject.py +208 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/MSVSSettings.py +1063 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/MSVSToolFile.py +58 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/MSVSUserFile.py +147 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/MSVSUtil.py +267 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/MSVSVersion.py +409 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/__init__.py +537 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/__init__.pyc +0 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/common.py +521 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/common.pyc +0 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/easy_xml.py +157 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/flock_tool.py +49 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/generator/__init__.py +0 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/generator/__init__.pyc +0 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/generator/android.py +1069 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/generator/cmake.py +1143 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/generator/dump_dependency_json.py +81 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/generator/eclipse.py +335 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/generator/gypd.py +87 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/generator/gypsh.py +56 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/generator/make.py +2181 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/generator/make.pyc +0 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/generator/msvs.py +3335 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/generator/ninja.py +2156 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/generator/xcode.py +1224 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/generator/xcode.pyc +0 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/input.py +2809 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/input.pyc +0 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/mac_tool.py +510 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/msvs_emulation.py +972 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/ninja_syntax.py +160 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/ordered_dict.py +289 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/win_tool.py +292 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/xcode_emulation.py +1440 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/xcode_emulation.pyc +0 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/xcodeproj_file.py +2889 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/xcodeproj_file.pyc +0 -0
- data/ext/snowcrash/tools/gyp/pylib/gyp/xml_fix.py +69 -0
- data/ext/snowcrash/tools/gyp/pylintrc +307 -0
- data/ext/snowcrash/tools/gyp/samples/samples +81 -0
- data/ext/snowcrash/tools/gyp/samples/samples.bat +5 -0
- data/ext/snowcrash/tools/gyp/setup.py +19 -0
- data/ext/snowcrash/tools/gyp/tools/Xcode/Specifications/gyp.pbfilespec +27 -0
- data/ext/snowcrash/tools/gyp/tools/Xcode/Specifications/gyp.xclangspec +226 -0
- data/ext/snowcrash/tools/gyp/tools/emacs/gyp.el +252 -0
- data/ext/snowcrash/tools/gyp/tools/graphviz.py +100 -0
- data/ext/snowcrash/tools/gyp/tools/pretty_gyp.py +155 -0
- data/ext/snowcrash/tools/gyp/tools/pretty_sln.py +168 -0
- data/ext/snowcrash/tools/gyp/tools/pretty_vcproj.py +329 -0
- data/ext/snowcrash/tools/homebrew/snowcrash.rb +11 -0
- data/ext/snowcrash/vcbuild.bat +184 -0
- data/lib/redsnow.rb +31 -0
- data/lib/redsnow/binding.rb +132 -0
- data/lib/redsnow/blueprint.rb +365 -0
- data/lib/redsnow/object.rb +18 -0
- data/lib/redsnow/parseresult.rb +107 -0
- data/lib/redsnow/version.rb +4 -0
- data/provisioning.sh +20 -0
- data/redsnow.gemspec +35 -0
- data/test/_helper.rb +15 -0
- data/test/fixtures/sample-api-ast.json +97 -0
- data/test/fixtures/sample-api.apib +20 -0
- data/test/redsnow_binding_test.rb +35 -0
- data/test/redsnow_parseresult_test.rb +50 -0
- data/test/redsnow_test.rb +285 -0
- metadata +358 -0
@@ -0,0 +1,10 @@
|
|
1
|
+
# Do not edit. Generated by the configure script.
|
2
|
+
{ 'target_defaults': { 'cflags': [],
|
3
|
+
'default_configuration': 'Release',
|
4
|
+
'defines': [],
|
5
|
+
'include_dirs': [],
|
6
|
+
'libraries': []},
|
7
|
+
'variables': { 'host_arch': 'x64',
|
8
|
+
'libsnowcrash_type': 'shared_library',
|
9
|
+
'python': '/usr/bin/python',
|
10
|
+
'target_arch': 'x64'}}
|
@@ -0,0 +1,213 @@
|
|
1
|
+
#!/usr/bin/env python
|
2
|
+
#
|
3
|
+
# Attribution Notice
|
4
|
+
# ------------------
|
5
|
+
# This file uses parts of Node.js `configure`.
|
6
|
+
# Please refer to https://github.com/joyent/node.
|
7
|
+
#
|
8
|
+
import optparse
|
9
|
+
import os
|
10
|
+
import pprint
|
11
|
+
import re
|
12
|
+
import shlex
|
13
|
+
import subprocess
|
14
|
+
import sys
|
15
|
+
import platform
|
16
|
+
|
17
|
+
CC = os.environ.get('CC', 'cc')
|
18
|
+
|
19
|
+
root_dir = os.path.dirname(__file__)
|
20
|
+
build_dir = './build'
|
21
|
+
|
22
|
+
# Parse options
|
23
|
+
parser = optparse.OptionParser()
|
24
|
+
parser.add_option("--debug",
|
25
|
+
action="store_true",
|
26
|
+
dest="debug",
|
27
|
+
help="Also build the debug build.")
|
28
|
+
|
29
|
+
parser.add_option("--dest-cpu",
|
30
|
+
action="store",
|
31
|
+
dest="dest_cpu",
|
32
|
+
help="CPU architecture to build for. Valid values are: ia32, x64.")
|
33
|
+
|
34
|
+
parser.add_option("--shared",
|
35
|
+
action="store_true",
|
36
|
+
dest="shared",
|
37
|
+
help="Build and use shared libsnowcrash instead of static one.")
|
38
|
+
|
39
|
+
parser.add_option("--include-integration-tests",
|
40
|
+
action="store_true",
|
41
|
+
dest="include_integration_tests",
|
42
|
+
help="Configure for integration testing using Cucumber")
|
43
|
+
|
44
|
+
(options, args) = parser.parse_args()
|
45
|
+
|
46
|
+
def write(filename, data):
|
47
|
+
filename = os.path.join(root_dir, filename)
|
48
|
+
print "creating ", filename
|
49
|
+
f = open(filename, 'w+')
|
50
|
+
f.write(data)
|
51
|
+
|
52
|
+
def cc_macros():
|
53
|
+
"""Checks predefined macros using the CC command."""
|
54
|
+
|
55
|
+
try:
|
56
|
+
p = subprocess.Popen(shlex.split(CC) + ['-dM', '-E', '-'],
|
57
|
+
stdin=subprocess.PIPE,
|
58
|
+
stdout=subprocess.PIPE,
|
59
|
+
stderr=subprocess.PIPE)
|
60
|
+
except OSError:
|
61
|
+
print '''Configure error: No acceptable C compiler found!
|
62
|
+
|
63
|
+
Please make sure you have a C compiler installed on your system and/or
|
64
|
+
consider adjusting the CC environment variable if you installed
|
65
|
+
it in a non-standard prefix.
|
66
|
+
'''
|
67
|
+
sys.exit()
|
68
|
+
|
69
|
+
p.stdin.write('\n')
|
70
|
+
out = p.communicate()[0]
|
71
|
+
|
72
|
+
out = str(out).split('\n')
|
73
|
+
|
74
|
+
k = {}
|
75
|
+
for line in out:
|
76
|
+
lst = shlex.split(line)
|
77
|
+
if len(lst) > 2:
|
78
|
+
key = lst[1]
|
79
|
+
val = lst[2]
|
80
|
+
k[key] = val
|
81
|
+
return k
|
82
|
+
|
83
|
+
def host_arch_cc():
|
84
|
+
"""Host architecture check using the CC command."""
|
85
|
+
|
86
|
+
k = cc_macros()
|
87
|
+
|
88
|
+
matchup = {
|
89
|
+
'__x86_64__' : 'x64',
|
90
|
+
'__i386__' : 'ia32',
|
91
|
+
'__arm__' : 'arm',
|
92
|
+
}
|
93
|
+
|
94
|
+
rtn = 'ia32' # default
|
95
|
+
|
96
|
+
for i in matchup:
|
97
|
+
if i in k and k[i] != '0':
|
98
|
+
rtn = matchup[i]
|
99
|
+
break
|
100
|
+
|
101
|
+
return rtn
|
102
|
+
|
103
|
+
def host_arch_win():
|
104
|
+
"""Host architecture check using environ vars (better way to do this?)"""
|
105
|
+
|
106
|
+
arch = os.environ.get('PROCESSOR_ARCHITECTURE', 'x86')
|
107
|
+
|
108
|
+
matchup = {
|
109
|
+
'AMD64' : 'x64',
|
110
|
+
'x86' : 'ia32',
|
111
|
+
'arm' : 'arm',
|
112
|
+
}
|
113
|
+
|
114
|
+
return matchup.get(arch, 'ia32')
|
115
|
+
|
116
|
+
def configure_snowcrash(o):
|
117
|
+
# Build configuration
|
118
|
+
o['default_configuration'] = 'Debug' if options.debug else 'Release'
|
119
|
+
|
120
|
+
# Architecture
|
121
|
+
host_arch = host_arch_win() if os.name == 'nt' else host_arch_cc()
|
122
|
+
target_arch = options.dest_cpu or host_arch
|
123
|
+
o['variables']['host_arch'] = host_arch
|
124
|
+
o['variables']['target_arch'] = target_arch
|
125
|
+
o['variables']['libsnowcrash_type'] = 'shared_library' if options.shared else 'static_library'
|
126
|
+
|
127
|
+
#
|
128
|
+
# Cucumber testing environment
|
129
|
+
#
|
130
|
+
# TODO: use bundle check
|
131
|
+
if options.include_integration_tests:
|
132
|
+
print "Installing dependencies for integration tests..."
|
133
|
+
try:
|
134
|
+
if sys.platform == 'win32':
|
135
|
+
subprocess.call(["bundle.bat", "install"])
|
136
|
+
else:
|
137
|
+
subprocess.call(["bundle", "install"])
|
138
|
+
except OSError as e:
|
139
|
+
if e.errno == os.errno.ENOENT:
|
140
|
+
raise RuntimeError(
|
141
|
+
"Integration test dependecies rely on Ruby Bundler "
|
142
|
+
"but it cannot be find in the system $PATH. "
|
143
|
+
"Please make sure to install Bundler or/and to "
|
144
|
+
"add it to the $PATH."
|
145
|
+
)
|
146
|
+
else:
|
147
|
+
raise
|
148
|
+
|
149
|
+
#
|
150
|
+
# config.gypi
|
151
|
+
#
|
152
|
+
output = {
|
153
|
+
'variables': { 'python': sys.executable },
|
154
|
+
'include_dirs': [],
|
155
|
+
'libraries': [],
|
156
|
+
'defines': [],
|
157
|
+
'cflags': [],
|
158
|
+
}
|
159
|
+
|
160
|
+
configure_snowcrash(output)
|
161
|
+
|
162
|
+
# variables should be a root level element,
|
163
|
+
# move everything else to target_defaults
|
164
|
+
variables = output['variables']
|
165
|
+
del output['variables']
|
166
|
+
output = {
|
167
|
+
'variables': variables,
|
168
|
+
'target_defaults': output
|
169
|
+
}
|
170
|
+
|
171
|
+
write('config.gypi', "# Do not edit. Generated by the configure script.\n" +
|
172
|
+
pprint.pformat(output, indent=2) + "\n")
|
173
|
+
|
174
|
+
#
|
175
|
+
# config.mk
|
176
|
+
#
|
177
|
+
config = {
|
178
|
+
'BUILDTYPE': 'Debug' if options.debug else 'Release',
|
179
|
+
'PYTHON': sys.executable,
|
180
|
+
'BUILD_DIR': build_dir,
|
181
|
+
'INTEGRATION_TESTS': '1' if options.include_integration_tests else ''
|
182
|
+
}
|
183
|
+
config = '\n'.join(map('='.join, config.iteritems())) + '\n'
|
184
|
+
|
185
|
+
write('config.mk',
|
186
|
+
'# Do not edit. Generated by the configure script.\n' + config)
|
187
|
+
|
188
|
+
#
|
189
|
+
# Gyp call
|
190
|
+
#
|
191
|
+
print "creating makefiles"
|
192
|
+
|
193
|
+
gyp_args = ['--generator-output', build_dir, '--depth', '.']
|
194
|
+
if sys.platform == 'win32':
|
195
|
+
# Windows
|
196
|
+
gyp_args.extend(['-f', 'msvs'])
|
197
|
+
else:
|
198
|
+
# Posix systems
|
199
|
+
gyp_args.extend(['-f', 'make'])
|
200
|
+
|
201
|
+
# Include common.gypi and config.gypi
|
202
|
+
if sys.platform == 'win32':
|
203
|
+
options_fn = os.path.join(root_dir, 'config.gypi')
|
204
|
+
else:
|
205
|
+
options_fn = os.path.join(os.path.abspath(root_dir), 'config.gypi')
|
206
|
+
|
207
|
+
if os.path.exists(options_fn):
|
208
|
+
gyp_args.extend(['-I', options_fn])
|
209
|
+
|
210
|
+
subprocess.call([sys.executable, 'tools/gyp/gyp_main.py'] + gyp_args)
|
211
|
+
|
212
|
+
# All done
|
213
|
+
print "All OK."
|
@@ -0,0 +1,15 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
|
3
|
+
# GCC 4.7
|
4
|
+
sudo apt-get update -y
|
5
|
+
sudo apt-get install -y python-software-properties
|
6
|
+
sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
|
7
|
+
sudo apt-get update -y
|
8
|
+
sudo apt-get install -y gcc-4.7 g++-4.7 gdb build-essential git-core
|
9
|
+
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.6 60 --slave /usr/bin/g++ g++ /usr/bin/g++-4.6
|
10
|
+
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.7 70 --slave /usr/bin/g++ g++ /usr/bin/g++-4.7
|
11
|
+
|
12
|
+
#sudo update-alternatives --config gcc
|
13
|
+
|
14
|
+
# Ruby
|
15
|
+
gem install bundler
|
@@ -0,0 +1,141 @@
|
|
1
|
+
{
|
2
|
+
"includes": [
|
3
|
+
"common.gypi"
|
4
|
+
],
|
5
|
+
|
6
|
+
'targets' : [
|
7
|
+
{
|
8
|
+
'target_name': 'sundown',
|
9
|
+
'type': 'static_library',
|
10
|
+
'include_dirs': [
|
11
|
+
'sundown/src',
|
12
|
+
'sundown/html',
|
13
|
+
],
|
14
|
+
'sources': [
|
15
|
+
'sundown/src/autolink.c',
|
16
|
+
'sundown/src/buffer.c',
|
17
|
+
'sundown/html/houdini_href_e.c',
|
18
|
+
'sundown/html/houdini_html_e.c',
|
19
|
+
'sundown/html/html.c',
|
20
|
+
'sundown/html/html_smartypants.c',
|
21
|
+
'sundown/src/markdown.c',
|
22
|
+
'sundown/src/stack.c',
|
23
|
+
'sundown/src/src_map.c'
|
24
|
+
]
|
25
|
+
},
|
26
|
+
{
|
27
|
+
'target_name': 'libsnowcrash',
|
28
|
+
'type': '<(libsnowcrash_type)',
|
29
|
+
'include_dirs': [
|
30
|
+
'src',
|
31
|
+
'sundown/src',
|
32
|
+
'sundown/src/html'
|
33
|
+
],
|
34
|
+
'sources': [
|
35
|
+
'src/HTTP.cc',
|
36
|
+
'src/MarkdownBlock.cc',
|
37
|
+
'src/MarkdownParser.cc',
|
38
|
+
'src/Parser.cc',
|
39
|
+
'src/ParserCore.cc',
|
40
|
+
'src/RegexMatch.h',
|
41
|
+
'src/Serialize.cc',
|
42
|
+
'src/Serialize.h',
|
43
|
+
'src/SerializeJSON.cc',
|
44
|
+
'src/SerializeYAML.cc',
|
45
|
+
'src/UriTemplateParser.cc',
|
46
|
+
'src/snowcrash.cc',
|
47
|
+
'src/csnowcrash.cc',
|
48
|
+
'src/CBlueprint.cc',
|
49
|
+
'src/CSourceAnnotation.cc'
|
50
|
+
],
|
51
|
+
'conditions': [
|
52
|
+
[ 'OS=="win"',
|
53
|
+
{ 'sources': [ 'src/win/RegexMatch.cc' ] },
|
54
|
+
{ 'sources': [ 'src/posix/RegexMatch.cc' ] } # OS != Windows
|
55
|
+
]
|
56
|
+
],
|
57
|
+
'dependencies': [
|
58
|
+
'sundown'
|
59
|
+
]
|
60
|
+
},
|
61
|
+
{
|
62
|
+
'target_name': 'test-libsnowcrash',
|
63
|
+
'type': 'executable',
|
64
|
+
'include_dirs': [
|
65
|
+
'src',
|
66
|
+
'test',
|
67
|
+
'test/vendor/Catch/include',
|
68
|
+
'sundown/src',
|
69
|
+
'sundown/src/html'
|
70
|
+
],
|
71
|
+
'sources': [
|
72
|
+
'test/test-ActionParser.cc',
|
73
|
+
'test/test-AssetParser.cc',
|
74
|
+
'test/test-Blueprint.cc',
|
75
|
+
'test/test-BlueprintParser.cc',
|
76
|
+
'test/test-HeaderParser.cc',
|
77
|
+
'test/test-Indentation.cc',
|
78
|
+
'test/test-ListUtility.cc',
|
79
|
+
'test/test-MarkdownBlock.cc',
|
80
|
+
'test/test-MarkdownParser.cc',
|
81
|
+
'test/test-ParameterDefinitonParser.cc',
|
82
|
+
'test/test-ParametersParser.cc',
|
83
|
+
'test/test-Parser.cc',
|
84
|
+
'test/test-PayloadParser.cc',
|
85
|
+
'test/test-RegexMatch.cc',
|
86
|
+
'test/test-ResouceGroupParser.cc',
|
87
|
+
'test/test-ResourceParser.cc',
|
88
|
+
'test/test-SymbolIdentifier.cc',
|
89
|
+
'test/test-SymbolTable.cc',
|
90
|
+
'test/test-Warnings.cc',
|
91
|
+
'test/test-csnowcrash.cc',
|
92
|
+
'test/test-UriTemplateParser.cc',
|
93
|
+
'test/test-snowcrash.cc'
|
94
|
+
],
|
95
|
+
'dependencies': [
|
96
|
+
'libsnowcrash',
|
97
|
+
'sundown'
|
98
|
+
]
|
99
|
+
},
|
100
|
+
|
101
|
+
{
|
102
|
+
'target_name': 'snowcrash',
|
103
|
+
'type': 'executable',
|
104
|
+
'include_dirs': [
|
105
|
+
'src',
|
106
|
+
'src/snowcrash',
|
107
|
+
'cmdline'
|
108
|
+
],
|
109
|
+
'sources': [
|
110
|
+
'src/snowcrash/snowcrash.cc'
|
111
|
+
],
|
112
|
+
'dependencies': [
|
113
|
+
'libsnowcrash',
|
114
|
+
'sundown'
|
115
|
+
]
|
116
|
+
}
|
117
|
+
],
|
118
|
+
'conditions': [
|
119
|
+
['OS in "mac linux"', {
|
120
|
+
'targets': [
|
121
|
+
{
|
122
|
+
'target_name': 'perf-libsnowcrash',
|
123
|
+
'type': 'executable',
|
124
|
+
'include_dirs': [
|
125
|
+
'src',
|
126
|
+
'cmdline',
|
127
|
+
'test',
|
128
|
+
'test/performance',
|
129
|
+
],
|
130
|
+
'sources': [
|
131
|
+
'test/performance/perf-snowcrash.cc'
|
132
|
+
],
|
133
|
+
'dependencies': [
|
134
|
+
'libsnowcrash',
|
135
|
+
'sundown'
|
136
|
+
]
|
137
|
+
}
|
138
|
+
]
|
139
|
+
}]
|
140
|
+
]
|
141
|
+
}
|
@@ -0,0 +1,503 @@
|
|
1
|
+
//
|
2
|
+
// ActionParser.h
|
3
|
+
// snowcrash
|
4
|
+
//
|
5
|
+
// Created by Zdenek Nemec on 5/4/13.
|
6
|
+
// Copyright (c) 2013 Apiary Inc. All rights reserved.
|
7
|
+
//
|
8
|
+
|
9
|
+
#ifndef SNOWCRASH_ACTIONPARSER_H
|
10
|
+
#define SNOWCRASH_ACTIONPARSER_H
|
11
|
+
|
12
|
+
#include "BlueprintParserCore.h"
|
13
|
+
#include "Blueprint.h"
|
14
|
+
#include "RegexMatch.h"
|
15
|
+
#include "PayloadParser.h"
|
16
|
+
#include "HeaderParser.h"
|
17
|
+
#include "ParametersParser.h"
|
18
|
+
#include "HTTP.h"
|
19
|
+
#include "DescriptionSectionUtility.h"
|
20
|
+
|
21
|
+
namespace snowcrashconst {
|
22
|
+
|
23
|
+
/** Nameless action matching regex */
|
24
|
+
const char* const ActionHeaderRegex = "^[[:blank:]]*" HTTP_REQUEST_METHOD "[[:blank:]]*" URI_TEMPLATE "?$";
|
25
|
+
|
26
|
+
/** Named action matching regex */
|
27
|
+
const char* const NamedActionHeaderRegex = "^[[:blank:]]*" SYMBOL_IDENTIFIER "\\[" HTTP_REQUEST_METHOD "]$";
|
28
|
+
}
|
29
|
+
|
30
|
+
namespace snowcrash {
|
31
|
+
|
32
|
+
// Method signature
|
33
|
+
enum ActionSignature {
|
34
|
+
UndefinedActionSignature,
|
35
|
+
NoActionSignature,
|
36
|
+
MethodActionSignature, // # GET
|
37
|
+
MethodURIActionSignature, // # GET /uri
|
38
|
+
NamedActionSignature // # My Method [GET]
|
39
|
+
};
|
40
|
+
|
41
|
+
// Query method signature
|
42
|
+
FORCEINLINE ActionSignature GetActionSignature(const MarkdownBlock& block,
|
43
|
+
Name& name,
|
44
|
+
HTTPMethod& method) {
|
45
|
+
if (block.type != HeaderBlockType ||
|
46
|
+
block.content.empty())
|
47
|
+
return NoActionSignature;
|
48
|
+
|
49
|
+
CaptureGroups captureGroups;
|
50
|
+
if (RegexCapture(block.content, snowcrashconst::ActionHeaderRegex, captureGroups, 3)) {
|
51
|
+
// Nameless action
|
52
|
+
method = captureGroups[1];
|
53
|
+
URITemplate uri = captureGroups[2];
|
54
|
+
return (uri.empty()) ? MethodActionSignature : MethodURIActionSignature;
|
55
|
+
}
|
56
|
+
else if (RegexCapture(block.content, snowcrashconst::NamedActionHeaderRegex, captureGroups, 3)) {
|
57
|
+
// Named action
|
58
|
+
name = captureGroups[1];
|
59
|
+
TrimString(name);
|
60
|
+
method = captureGroups[2];
|
61
|
+
return NamedActionSignature;
|
62
|
+
}
|
63
|
+
|
64
|
+
return NoActionSignature;
|
65
|
+
}
|
66
|
+
|
67
|
+
// Returns true if block has HTTP Method signature, false otherwise
|
68
|
+
FORCEINLINE bool HasActionSignature(const MarkdownBlock& block) {
|
69
|
+
|
70
|
+
if (block.type != HeaderBlockType ||
|
71
|
+
block.content.empty())
|
72
|
+
return false;
|
73
|
+
|
74
|
+
Name name;
|
75
|
+
HTTPMethod method;
|
76
|
+
return GetActionSignature(block, name, method) != NoActionSignature;
|
77
|
+
}
|
78
|
+
|
79
|
+
// Finds an action inside resource
|
80
|
+
FORCEINLINE Collection<Action>::iterator FindAction(Resource& resource,
|
81
|
+
const Action& action) {
|
82
|
+
return std::find_if(resource.actions.begin(),
|
83
|
+
resource.actions.end(),
|
84
|
+
std::bind2nd(MatchAction<Action>(), action));
|
85
|
+
}
|
86
|
+
|
87
|
+
//
|
88
|
+
// Classifier of internal list items, Payload context
|
89
|
+
//
|
90
|
+
template <>
|
91
|
+
FORCEINLINE SectionType ClassifyInternaListBlock<Action>(const BlockIterator& begin,
|
92
|
+
const BlockIterator& end) {
|
93
|
+
if (HasHeaderSignature(begin, end))
|
94
|
+
return HeadersSectionType;
|
95
|
+
|
96
|
+
if (HasParametersSignature(begin, end))
|
97
|
+
return ParametersSectionType;
|
98
|
+
|
99
|
+
Name name;
|
100
|
+
SourceData mediaType;
|
101
|
+
PayloadSignature payload = GetPayloadSignature(begin, end, name, mediaType);
|
102
|
+
if (payload == RequestPayloadSignature)
|
103
|
+
return RequestSectionType;
|
104
|
+
else if (payload == ResponsePayloadSignature)
|
105
|
+
return ResponseSectionType;
|
106
|
+
else if (payload == ObjectPayloadSignature)
|
107
|
+
return ObjectSectionType;
|
108
|
+
else if (payload == ModelPayloadSignature)
|
109
|
+
return ModelSectionType;
|
110
|
+
|
111
|
+
return UndefinedSectionType;
|
112
|
+
}
|
113
|
+
|
114
|
+
/** Children blocks classifier */
|
115
|
+
template <>
|
116
|
+
FORCEINLINE SectionType ClassifyChildrenListBlock<Action>(const BlockIterator& begin,
|
117
|
+
const BlockIterator& end) {
|
118
|
+
|
119
|
+
SectionType type = ClassifyInternaListBlock<Action>(begin, end);
|
120
|
+
if (type != UndefinedSectionType)
|
121
|
+
return type;
|
122
|
+
|
123
|
+
type = ClassifyChildrenListBlock<HeaderCollection>(begin, end);
|
124
|
+
if (type != UndefinedSectionType)
|
125
|
+
return type;
|
126
|
+
|
127
|
+
type = ClassifyChildrenListBlock<ParameterCollection>(begin, end);
|
128
|
+
if (type != UndefinedSectionType)
|
129
|
+
return type;
|
130
|
+
|
131
|
+
type = ClassifyChildrenListBlock<Payload>(begin, end);
|
132
|
+
if (type != UndefinedSectionType)
|
133
|
+
return type;
|
134
|
+
|
135
|
+
return UndefinedSectionType;
|
136
|
+
}
|
137
|
+
|
138
|
+
//
|
139
|
+
// Block Classifier, Action Context
|
140
|
+
//
|
141
|
+
template <>
|
142
|
+
FORCEINLINE SectionType ClassifyBlock<Action>(const BlockIterator& begin,
|
143
|
+
const BlockIterator& end,
|
144
|
+
const SectionType& context) {
|
145
|
+
|
146
|
+
if (HasActionSignature(*begin))
|
147
|
+
return (context == UndefinedSectionType) ? ActionSectionType : UndefinedSectionType;
|
148
|
+
|
149
|
+
if (HasResourceSignature(*begin) ||
|
150
|
+
HasResourceGroupSignature(*begin))
|
151
|
+
return UndefinedSectionType;
|
152
|
+
|
153
|
+
SectionType listSection = ClassifyInternaListBlock<Action>(begin, end);
|
154
|
+
if (listSection != UndefinedSectionType)
|
155
|
+
return listSection;
|
156
|
+
|
157
|
+
// Unrecognized list item at this level
|
158
|
+
if (begin->type == ListItemBlockBeginType)
|
159
|
+
return ForeignSectionType;
|
160
|
+
|
161
|
+
return (context == ActionSectionType) ? ActionSectionType : UndefinedSectionType;
|
162
|
+
}
|
163
|
+
|
164
|
+
//
|
165
|
+
// Action SectionType Parser
|
166
|
+
//
|
167
|
+
template<>
|
168
|
+
struct SectionParser<Action> {
|
169
|
+
|
170
|
+
static ParseSectionResult ParseSection(const BlueprintSection& section,
|
171
|
+
const BlockIterator& cur,
|
172
|
+
BlueprintParserCore& parser,
|
173
|
+
Action& action) {
|
174
|
+
|
175
|
+
ParseSectionResult result = std::make_pair(Result(), cur);
|
176
|
+
|
177
|
+
switch (section.type) {
|
178
|
+
case ActionSectionType:
|
179
|
+
result = HandleActionDescriptionBlock(section, cur, parser, action);
|
180
|
+
break;
|
181
|
+
|
182
|
+
case ParametersSectionType:
|
183
|
+
result = HandleParameters(section, cur, parser, action);
|
184
|
+
break;
|
185
|
+
|
186
|
+
case HeadersSectionType:
|
187
|
+
result = HandleDeprecatedHeaders(section, cur, parser, action);
|
188
|
+
break;
|
189
|
+
|
190
|
+
case RequestSectionType:
|
191
|
+
case ResponseSectionType:
|
192
|
+
result = HandlePayload(section, cur, parser, action);
|
193
|
+
break;
|
194
|
+
|
195
|
+
case ForeignSectionType:
|
196
|
+
result = HandleForeignSection<Action>(section, cur, parser.sourceData);
|
197
|
+
break;
|
198
|
+
|
199
|
+
case UndefinedSectionType:
|
200
|
+
result.second = CloseList(cur, section.bounds.second);
|
201
|
+
break;
|
202
|
+
|
203
|
+
case ModelSectionType:
|
204
|
+
case ObjectSectionType:
|
205
|
+
{
|
206
|
+
// ERR: Unexpected model definition
|
207
|
+
SourceCharactersBlock sourceBlock = CharacterMapForBlock(cur,
|
208
|
+
section.bounds.second,
|
209
|
+
section.bounds,
|
210
|
+
parser.sourceData);
|
211
|
+
result.first.error = Error("unexpected model definiton, a model can be only defined in the resource section",
|
212
|
+
SymbolError,
|
213
|
+
sourceBlock);
|
214
|
+
}
|
215
|
+
break;
|
216
|
+
|
217
|
+
default:
|
218
|
+
result.first.error = UnexpectedBlockError(section, cur, parser.sourceData);
|
219
|
+
break;
|
220
|
+
}
|
221
|
+
|
222
|
+
return result;
|
223
|
+
}
|
224
|
+
|
225
|
+
static void Finalize(const SectionBounds& bounds,
|
226
|
+
BlueprintParserCore& parser,
|
227
|
+
Action& action,
|
228
|
+
Result& result)
|
229
|
+
{
|
230
|
+
// Consolidate deprecated headers into subsequent payloads
|
231
|
+
if (!action.headers.empty()) {
|
232
|
+
InjectDeprecatedHeaders(action.headers, action.examples);
|
233
|
+
action.headers.clear();
|
234
|
+
}
|
235
|
+
|
236
|
+
// Check whether transaction example request is followed by a response
|
237
|
+
if (action.examples.size() > 1 &&
|
238
|
+
!action.examples.back().requests.empty() &&
|
239
|
+
action.examples.back().responses.empty()) {
|
240
|
+
// WARN: No response for request
|
241
|
+
|
242
|
+
std::stringstream ss;
|
243
|
+
ss << "action is missing a response for ";
|
244
|
+
if (action.examples.back().requests.back().name.empty())
|
245
|
+
ss << "a request";
|
246
|
+
else
|
247
|
+
ss << "the '" << action.examples.back().requests.back().name << "' request";
|
248
|
+
|
249
|
+
SourceCharactersBlock sourceBlock = CharacterMapForBlock(bounds.first, bounds.first, bounds, parser.sourceData);
|
250
|
+
result.warnings.push_back(Warning(ss.str(),
|
251
|
+
EmptyDefinitionWarning,
|
252
|
+
sourceBlock));
|
253
|
+
}
|
254
|
+
}
|
255
|
+
|
256
|
+
static ParseSectionResult HandleActionDescriptionBlock(const BlueprintSection& section,
|
257
|
+
const BlockIterator& cur,
|
258
|
+
BlueprintParserCore& parser,
|
259
|
+
Action& action) {
|
260
|
+
|
261
|
+
ParseSectionResult result = std::make_pair(Result(), cur);
|
262
|
+
BlockIterator sectionCur(cur);
|
263
|
+
|
264
|
+
if (cur->type == HeaderBlockType &&
|
265
|
+
cur == section.bounds.first) {
|
266
|
+
|
267
|
+
GetActionSignature(*cur, action.name, action.method);
|
268
|
+
result.second = ++sectionCur;
|
269
|
+
return result;
|
270
|
+
}
|
271
|
+
|
272
|
+
result = ParseDescriptionBlock<Action>(section,
|
273
|
+
sectionCur,
|
274
|
+
parser.sourceData,
|
275
|
+
action);
|
276
|
+
return result;
|
277
|
+
}
|
278
|
+
|
279
|
+
/** Parse Parameters section */
|
280
|
+
static ParseSectionResult HandleParameters(const BlueprintSection& section,
|
281
|
+
const BlockIterator& cur,
|
282
|
+
BlueprintParserCore& parser,
|
283
|
+
Action& action) {
|
284
|
+
ParameterCollection parameters;
|
285
|
+
ParseSectionResult result = ParametersParser::Parse(cur,
|
286
|
+
section.bounds.second,
|
287
|
+
section,
|
288
|
+
parser,
|
289
|
+
parameters);
|
290
|
+
if (result.first.error.code != Error::OK)
|
291
|
+
return result;
|
292
|
+
|
293
|
+
if (parameters.empty()) {
|
294
|
+
BlockIterator nameBlock = ListItemNameBlock(cur, section.bounds.second);
|
295
|
+
SourceCharactersBlock sourceBlock = CharacterMapForBlock(nameBlock, cur, section.bounds, parser.sourceData);
|
296
|
+
result.first.warnings.push_back(Warning(snowcrashconst::NoParametersMessage,
|
297
|
+
FormattingWarning,
|
298
|
+
sourceBlock));
|
299
|
+
}
|
300
|
+
else {
|
301
|
+
action.parameters.insert(action.parameters.end(), parameters.begin(), parameters.end());
|
302
|
+
}
|
303
|
+
|
304
|
+
return result;
|
305
|
+
}
|
306
|
+
|
307
|
+
/**
|
308
|
+
* \brief Parse action payload
|
309
|
+
* \param section Actual section being parsed.
|
310
|
+
* \param cur Cursor within the section boundaries.
|
311
|
+
* \param parser A parser's instance.
|
312
|
+
* \param action An output buffer to store parsed payload into.
|
313
|
+
* \return A block parser section result.
|
314
|
+
*/
|
315
|
+
static ParseSectionResult HandlePayload(const BlueprintSection& section,
|
316
|
+
const BlockIterator& cur,
|
317
|
+
BlueprintParserCore& parser,
|
318
|
+
Action& action)
|
319
|
+
{
|
320
|
+
Payload payload;
|
321
|
+
ParseSectionResult result = PayloadParser::Parse(cur,
|
322
|
+
section.bounds.second,
|
323
|
+
section,
|
324
|
+
parser,
|
325
|
+
payload);
|
326
|
+
if (result.first.error.code != Error::OK)
|
327
|
+
return result;
|
328
|
+
|
329
|
+
// Create transaction example if needed
|
330
|
+
if (action.examples.empty()) {
|
331
|
+
action.examples.push_back(TransactionExample());
|
332
|
+
}
|
333
|
+
else if (section.type == RequestSectionType) {
|
334
|
+
// Automatic request response pairing:
|
335
|
+
// If a request follows a response create a new transaction example
|
336
|
+
if (!action.examples.back().responses.empty()) {
|
337
|
+
action.examples.push_back(TransactionExample());
|
338
|
+
}
|
339
|
+
}
|
340
|
+
|
341
|
+
BlockIterator nameBlock = ListItemNameBlock(cur, section.bounds.second);
|
342
|
+
|
343
|
+
// Check for duplicate
|
344
|
+
if (IsPayloadDuplicate(section.type, payload, action.examples.back())) {
|
345
|
+
// WARN: duplicate payload
|
346
|
+
std::stringstream ss;
|
347
|
+
ss << SectionName(section.type) << " payload `" << payload.name << "`";
|
348
|
+
ss << " already defined for `" << action.method << "` method";
|
349
|
+
|
350
|
+
SourceCharactersBlock sourceBlock = CharacterMapForBlock(nameBlock, cur, section.bounds, parser.sourceData);
|
351
|
+
result.first.warnings.push_back(Warning(ss.str(),
|
352
|
+
DuplicateWarning,
|
353
|
+
sourceBlock));
|
354
|
+
}
|
355
|
+
|
356
|
+
// Check payload integrity
|
357
|
+
CheckPayload(section.type, payload, action.method, nameBlock->sourceMap, parser.sourceData, result.first);
|
358
|
+
|
359
|
+
// Inject parsed payload into the action
|
360
|
+
if (section.type == RequestSectionType) {
|
361
|
+
action.examples.back().requests.push_back(payload);
|
362
|
+
}
|
363
|
+
else if (section.type == ResponseSectionType) {
|
364
|
+
action.examples.back().responses.push_back(payload);
|
365
|
+
}
|
366
|
+
|
367
|
+
// Check header duplicates
|
368
|
+
CheckHeaderDuplicates(action, payload, nameBlock->sourceMap, parser.sourceData, result.first);
|
369
|
+
|
370
|
+
return result;
|
371
|
+
}
|
372
|
+
|
373
|
+
|
374
|
+
/**
|
375
|
+
* \brief Check & report payload validity.
|
376
|
+
* \param section A section of the payload.
|
377
|
+
* \param sourceMap Payload signature source map.
|
378
|
+
* \param payload The payload to be checked.
|
379
|
+
*/
|
380
|
+
static void CheckPayload(const SectionType& section,
|
381
|
+
const Payload& payload,
|
382
|
+
const HTTPMethod method,
|
383
|
+
const SourceDataBlock& sourceMap,
|
384
|
+
const SourceData& sourceData,
|
385
|
+
Result& result) {
|
386
|
+
|
387
|
+
bool warnEmptyBody = false;
|
388
|
+
|
389
|
+
std::string contentLength;
|
390
|
+
std::string transferEncoding;
|
391
|
+
|
392
|
+
for (Collection<Header>::const_iterator it = payload.headers.begin();
|
393
|
+
it != payload.headers.end();
|
394
|
+
++it) {
|
395
|
+
|
396
|
+
if (it->first == HTTPHeaderName::ContentLength) {
|
397
|
+
contentLength = it->second;
|
398
|
+
}
|
399
|
+
|
400
|
+
if (it->first == HTTPHeaderName::TransferEncoding) {
|
401
|
+
transferEncoding = it->second;
|
402
|
+
}
|
403
|
+
}
|
404
|
+
|
405
|
+
if (section == RequestSectionType) {
|
406
|
+
|
407
|
+
if (payload.body.empty()) {
|
408
|
+
|
409
|
+
// Warn when content-length or transfer-encoding is specified or both headers and body are empty
|
410
|
+
if (payload.headers.empty()) {
|
411
|
+
warnEmptyBody = true;
|
412
|
+
}
|
413
|
+
else {
|
414
|
+
warnEmptyBody = !contentLength.empty() ||
|
415
|
+
!transferEncoding.empty();
|
416
|
+
}
|
417
|
+
|
418
|
+
if (warnEmptyBody) {
|
419
|
+
// WARN: empty body
|
420
|
+
std::stringstream ss;
|
421
|
+
ss << "empty " << SectionName(section) << " " << SectionName(BodySectionType);
|
422
|
+
|
423
|
+
if (!contentLength.empty()) {
|
424
|
+
ss << ", expected " << SectionName(BodySectionType) << " for '" << contentLength << "' Content-Length";
|
425
|
+
}
|
426
|
+
else if (!transferEncoding.empty()) {
|
427
|
+
ss << ", expected " << SectionName(BodySectionType) << " for '" << transferEncoding << "' Transfer-Encoding";
|
428
|
+
}
|
429
|
+
|
430
|
+
result.warnings.push_back(Warning(ss.str(),
|
431
|
+
EmptyDefinitionWarning,
|
432
|
+
MapSourceDataBlock(sourceMap, sourceData)));
|
433
|
+
}
|
434
|
+
|
435
|
+
}
|
436
|
+
}
|
437
|
+
else if (section == ResponseSectionType) {
|
438
|
+
// Check status code
|
439
|
+
HTTPStatusCode code = 0;
|
440
|
+
|
441
|
+
if (!payload.name.empty()) {
|
442
|
+
std::stringstream(payload.name) >> code;
|
443
|
+
}
|
444
|
+
|
445
|
+
StatusCodeTraits statusCodeTraits = GetStatusCodeTrait(code);
|
446
|
+
HTTPMethodTraits methodTraits = GetMethodTrait(method);
|
447
|
+
|
448
|
+
if ((!statusCodeTraits.allowBody || !methodTraits.allowBody) && !payload.body.empty()) {
|
449
|
+
// WARN: not empty body
|
450
|
+
|
451
|
+
if (!statusCodeTraits.allowBody) {
|
452
|
+
std::stringstream ss;
|
453
|
+
ss << "the " << code << " response MUST NOT include a " << SectionName(BodySectionType);
|
454
|
+
result.warnings.push_back(Warning(ss.str(),
|
455
|
+
EmptyDefinitionWarning,
|
456
|
+
MapSourceDataBlock(sourceMap, sourceData)));
|
457
|
+
}
|
458
|
+
|
459
|
+
// WARN: Edge case for 2xx CONNECT
|
460
|
+
if (method == HTTPMethodName::Connect && code/100 == 2) {
|
461
|
+
std::stringstream ss;
|
462
|
+
ss << "the response for " << code << " " << method << " request MUST NOT include a " << SectionName(BodySectionType);
|
463
|
+
result.warnings.push_back(Warning(ss.str(),
|
464
|
+
EmptyDefinitionWarning,
|
465
|
+
MapSourceDataBlock(sourceMap, sourceData)));
|
466
|
+
|
467
|
+
}
|
468
|
+
else if (method != HTTPMethodName::Connect && !methodTraits.allowBody) {
|
469
|
+
std::stringstream ss;
|
470
|
+
ss << "the response for " << method << " request MUST NOT include a " << SectionName(BodySectionType);
|
471
|
+
result.warnings.push_back(Warning(ss.str(),
|
472
|
+
EmptyDefinitionWarning,
|
473
|
+
MapSourceDataBlock(sourceMap, sourceData)));
|
474
|
+
}
|
475
|
+
|
476
|
+
return;
|
477
|
+
}
|
478
|
+
}
|
479
|
+
}
|
480
|
+
|
481
|
+
/**
|
482
|
+
* Checks whether given section payload has duplicate within its transaction examples
|
483
|
+
* \return True when a duplicate is found, false otherwise.
|
484
|
+
*/
|
485
|
+
static bool IsPayloadDuplicate(const SectionType& section, const Payload& payload, TransactionExample& example) {
|
486
|
+
|
487
|
+
if (section == RequestSectionType) {
|
488
|
+
Collection<Request>::const_iterator duplicate = FindRequest(example, payload);
|
489
|
+
return duplicate != example.requests.end();
|
490
|
+
}
|
491
|
+
else if (section == ResponseSectionType) {
|
492
|
+
Collection<Response>::const_iterator duplicate = FindResponse(example, payload);
|
493
|
+
return duplicate != example.responses.end();
|
494
|
+
}
|
495
|
+
|
496
|
+
return false;
|
497
|
+
}
|
498
|
+
};
|
499
|
+
|
500
|
+
typedef BlockParser<Action, SectionParser<Action> > ActionParser;
|
501
|
+
}
|
502
|
+
|
503
|
+
#endif
|