Multipart support thanks to http_server

This commit is contained in:
thosakwe 2016-09-24 14:30:01 -04:00
parent 5c0ee725d1
commit 9a06489be5
15 changed files with 529 additions and 1118 deletions

View file

@ -5,318 +5,350 @@
<entry key="analyzer">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/analyzer-0.27.2/lib" />
<option value="$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/analyzer-0.27.2/lib" />
</list>
</value>
</entry>
<entry key="args">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/args-0.13.4/lib" />
<option value="$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/args-0.13.4/lib" />
</list>
</value>
</entry>
<entry key="async">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/async-1.10.0/lib" />
<option value="$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/async-1.10.0/lib" />
</list>
</value>
</entry>
<entry key="barback">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/barback-0.15.2+7/lib" />
<option value="$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/barback-0.15.2+7/lib" />
</list>
</value>
</entry>
<entry key="boolean_selector">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/boolean_selector-1.0.1/lib" />
<option value="$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/boolean_selector-1.0.1/lib" />
</list>
</value>
</entry>
<entry key="charcode">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/charcode-1.1.0/lib" />
<option value="$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/charcode-1.1.0/lib" />
</list>
</value>
</entry>
<entry key="collection">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/collection-1.5.1/lib" />
<option value="$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/collection-1.9.1/lib" />
</list>
</value>
</entry>
<entry key="convert">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/convert-1.0.1/lib" />
<option value="$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/convert-1.0.1/lib" />
</list>
</value>
</entry>
<entry key="crypto">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/crypto-1.0.0/lib" />
<option value="$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/crypto-1.0.0/lib" />
</list>
</value>
</entry>
<entry key="csslib">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/csslib-0.12.2/lib" />
<option value="$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/csslib-0.12.2/lib" />
</list>
</value>
</entry>
<entry key="glob">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/glob-1.1.2/lib" />
<option value="$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/glob-1.1.2/lib" />
</list>
</value>
</entry>
<entry key="html">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/html-0.12.2+1/lib" />
<option value="$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/html-0.12.2+1/lib" />
</list>
</value>
</entry>
<entry key="http">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/http-0.11.3+3/lib" />
<option value="$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/http-0.11.3+3/lib" />
</list>
</value>
</entry>
<entry key="http_multi_server">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/http_multi_server-2.0.1/lib" />
<option value="$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/http_multi_server-2.0.1/lib" />
</list>
</value>
</entry>
<entry key="http_parser">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/http_parser-2.2.1/lib" />
<option value="$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/http_parser-2.2.1/lib" />
</list>
</value>
</entry>
<entry key="http_server">
<value>
<list>
<option value="$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/http_server-0.9.6/lib" />
</list>
</value>
</entry>
<entry key="json_god">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/json_god-1.0.0/lib" />
<option value="$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/json_god-2.0.0-beta/lib" />
</list>
</value>
</entry>
<entry key="json_schema">
<value>
<list>
<option value="$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/json_schema-1.0.4/lib" />
</list>
</value>
</entry>
<entry key="logging">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/logging-0.11.2/lib" />
<option value="$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/logging-0.11.2/lib" />
</list>
</value>
</entry>
<entry key="matcher">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/matcher-0.12.0+2/lib" />
<option value="$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/matcher-0.12.0+2/lib" />
</list>
</value>
</entry>
<entry key="mime">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/mime-0.9.3/lib" />
<option value="$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/mime-0.9.3/lib" />
</list>
</value>
</entry>
<entry key="package_config">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/package_config-0.1.3/lib" />
<option value="$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/package_config-0.1.3/lib" />
</list>
</value>
</entry>
<entry key="package_resolver">
<value>
<list>
<option value="$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/package_resolver-1.0.2/lib" />
</list>
</value>
</entry>
<entry key="path">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/path-1.3.9/lib" />
<option value="$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/path-1.3.9/lib" />
</list>
</value>
</entry>
<entry key="plugin">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/plugin-0.1.0/lib" />
<option value="$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/plugin-0.1.0/lib" />
</list>
</value>
</entry>
<entry key="pool">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/pool-1.2.3/lib" />
<option value="$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/pool-1.2.3/lib" />
</list>
</value>
</entry>
<entry key="pub_semver">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/pub_semver-1.2.4/lib" />
<option value="$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/pub_semver-1.2.4/lib" />
</list>
</value>
</entry>
<entry key="shelf">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/shelf-0.6.5/lib" />
<option value="$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/shelf-0.6.5/lib" />
</list>
</value>
</entry>
<entry key="shelf_packages_handler">
<value>
<list>
<option value="$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/shelf_packages_handler-1.0.0/lib" />
</list>
</value>
</entry>
<entry key="shelf_static">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/shelf_static-0.2.3+3/lib" />
<option value="$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/shelf_static-0.2.3+3/lib" />
</list>
</value>
</entry>
<entry key="shelf_web_socket">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/shelf_web_socket-0.2.0/lib" />
<option value="$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/shelf_web_socket-0.2.0/lib" />
</list>
</value>
</entry>
<entry key="source_map_stack_trace">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/source_map_stack_trace-1.0.4/lib" />
<option value="$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/source_map_stack_trace-1.1.3/lib" />
</list>
</value>
</entry>
<entry key="source_maps">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/source_maps-0.10.1+1/lib" />
<option value="$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/source_maps-0.10.1+1/lib" />
</list>
</value>
</entry>
<entry key="source_span">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/source_span-1.2.2/lib" />
<option value="$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/source_span-1.2.2/lib" />
</list>
</value>
</entry>
<entry key="stack_trace">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/stack_trace-1.6.5/lib" />
<option value="$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/stack_trace-1.6.5/lib" />
</list>
</value>
</entry>
<entry key="stream_channel">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/stream_channel-1.3.1/lib" />
<option value="$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/stream_channel-1.3.1/lib" />
</list>
</value>
</entry>
<entry key="string_scanner">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/string_scanner-0.1.4+1/lib" />
<option value="$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/string_scanner-0.1.4+1/lib" />
</list>
</value>
</entry>
<entry key="test">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/test-0.12.13/lib" />
<option value="$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/test-0.12.15+6/lib" />
</list>
</value>
</entry>
<entry key="typed_data">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/typed_data-1.1.2/lib" />
<option value="$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/typed_data-1.1.2/lib" />
</list>
</value>
</entry>
<entry key="utf">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/utf-0.9.0+3/lib" />
<option value="$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/utf-0.9.0+3/lib" />
</list>
</value>
</entry>
<entry key="watcher">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/watcher-0.9.7/lib" />
<option value="$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/watcher-0.9.7/lib" />
</list>
</value>
</entry>
<entry key="web_socket_channel">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/web_socket_channel-1.0.2/lib" />
<option value="$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/web_socket_channel-1.0.2/lib" />
</list>
</value>
</entry>
<entry key="yaml">
<value>
<list>
<option value="$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/yaml-2.1.8/lib" />
<option value="$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/yaml-2.1.8/lib" />
</list>
</value>
</entry>
</option>
</properties>
<CLASSES>
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/analyzer-0.27.2/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/args-0.13.4/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/async-1.10.0/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/barback-0.15.2+7/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/boolean_selector-1.0.1/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/charcode-1.1.0/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/collection-1.5.1/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/convert-1.0.1/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/crypto-1.0.0/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/csslib-0.12.2/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/glob-1.1.2/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/html-0.12.2+1/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/http-0.11.3+3/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/http_multi_server-2.0.1/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/http_parser-2.2.1/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/json_god-1.0.0/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/logging-0.11.2/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/matcher-0.12.0+2/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/mime-0.9.3/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/package_config-0.1.3/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/path-1.3.9/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/plugin-0.1.0/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/pool-1.2.3/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/pub_semver-1.2.4/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/shelf-0.6.5/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/shelf_static-0.2.3+3/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/shelf_web_socket-0.2.0/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/source_map_stack_trace-1.0.4/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/source_maps-0.10.1+1/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/source_span-1.2.2/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/stack_trace-1.6.5/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/stream_channel-1.3.1/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/string_scanner-0.1.4+1/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/test-0.12.13/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/typed_data-1.1.2/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/utf-0.9.0+3/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/watcher-0.9.7/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/web_socket_channel-1.0.2/lib" />
<root url="file://$USER_HOME$/.pub-cache/hosted/pub.dartlang.org/yaml-2.1.8/lib" />
<root url="file://$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/analyzer-0.27.2/lib" />
<root url="file://$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/args-0.13.4/lib" />
<root url="file://$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/async-1.10.0/lib" />
<root url="file://$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/barback-0.15.2+7/lib" />
<root url="file://$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/boolean_selector-1.0.1/lib" />
<root url="file://$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/charcode-1.1.0/lib" />
<root url="file://$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/collection-1.9.1/lib" />
<root url="file://$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/convert-1.0.1/lib" />
<root url="file://$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/crypto-1.0.0/lib" />
<root url="file://$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/csslib-0.12.2/lib" />
<root url="file://$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/glob-1.1.2/lib" />
<root url="file://$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/html-0.12.2+1/lib" />
<root url="file://$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/http-0.11.3+3/lib" />
<root url="file://$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/http_multi_server-2.0.1/lib" />
<root url="file://$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/http_parser-2.2.1/lib" />
<root url="file://$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/http_server-0.9.6/lib" />
<root url="file://$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/json_god-2.0.0-beta/lib" />
<root url="file://$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/json_schema-1.0.4/lib" />
<root url="file://$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/logging-0.11.2/lib" />
<root url="file://$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/matcher-0.12.0+2/lib" />
<root url="file://$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/mime-0.9.3/lib" />
<root url="file://$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/package_config-0.1.3/lib" />
<root url="file://$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/package_resolver-1.0.2/lib" />
<root url="file://$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/path-1.3.9/lib" />
<root url="file://$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/plugin-0.1.0/lib" />
<root url="file://$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/pool-1.2.3/lib" />
<root url="file://$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/pub_semver-1.2.4/lib" />
<root url="file://$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/shelf-0.6.5/lib" />
<root url="file://$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/shelf_packages_handler-1.0.0/lib" />
<root url="file://$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/shelf_static-0.2.3+3/lib" />
<root url="file://$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/shelf_web_socket-0.2.0/lib" />
<root url="file://$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/source_map_stack_trace-1.1.3/lib" />
<root url="file://$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/source_maps-0.10.1+1/lib" />
<root url="file://$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/source_span-1.2.2/lib" />
<root url="file://$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/stack_trace-1.6.5/lib" />
<root url="file://$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/stream_channel-1.3.1/lib" />
<root url="file://$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/string_scanner-0.1.4+1/lib" />
<root url="file://$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/test-0.12.15+6/lib" />
<root url="file://$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/typed_data-1.1.2/lib" />
<root url="file://$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/utf-0.9.0+3/lib" />
<root url="file://$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/watcher-0.9.7/lib" />
<root url="file://$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/web_socket_channel-1.0.2/lib" />
<root url="file://$USER_HOME$/AppData/Roaming/Pub/Cache/hosted/pub.dartlang.org/yaml-2.1.8/lib" />
</CLASSES>
<SOURCES />
</library>

View file

@ -1,5 +1,5 @@
# Body Parser
![version 1.0.0-dev](https://img.shields.io/badge/version-1.0.0--dev-red.svg)
![version 1.0.0-dev+1](https://img.shields.io/badge/version-1.0.0--dev-red.svg)
**NOT YET PRODUCTION READY**
@ -68,6 +68,4 @@ Thank you for using this library. I hope you like it.
Feel free to follow me on Twitter:
[@thosakwe](http://twitter.com/thosakwe)
or
[@regios_tech](http://twitter.com/regios_tech)
[@_wapaa_](http://twitter.com/_wapaa_)

File diff suppressed because one or more lines are too long

View file

@ -4,161 +4,7 @@ library body_parser;
import 'dart:async';
import 'dart:convert';
import 'dart:io';
part 'file_upload_info.dart';
/// A representation of data from an incoming request.
class BodyParseResult {
/// The parsed body.
Map body = {};
/// The parsed query string.
Map query = {};
/// All files uploaded within this request.
List<FileUploadInfo> files = [];
}
/// Grabs data from an incoming request.
///
/// Supports urlencoded and JSON, as well as multipart/form-data uploads.
/// On a file upload request, only fields with the name **'file'** are processed
/// as files. Anything else is put in the body. You can change the upload file name
/// via the *fileUploadName* parameter. :)
Future<BodyParseResult> parseBody(HttpRequest request,
{String fileUploadName: 'file'}) async {
BodyParseResult result = new BodyParseResult();
ContentType contentType = request.headers.contentType;
// Parse body
if (contentType != null) {
if (contentType.mimeType == 'application/json')
result.body = JSON.decode(await request.transform(UTF8.decoder).join());
else if (contentType.mimeType == 'application/x-www-form-urlencoded') {
String body = await request.transform(UTF8.decoder).join();
buildMapFromUri(result.body, body);
}
}
// Parse query
RegExp queryRgx = new RegExp(r'\?(.+)$');
String uriString = request.requestedUri.toString();
if (queryRgx.hasMatch(uriString)) {
Match queryMatch = queryRgx.firstMatch(uriString);
buildMapFromUri(result.query, queryMatch.group(1));
}
// Accept file
if (contentType != null && request.method == 'POST') {
RegExp parseBoundaryRgx = new RegExp(
r'multipart\/form-data;\s*boundary=([^\s;]+)');
if (parseBoundaryRgx.hasMatch(contentType.toString())) {
Match boundaryMatch = parseBoundaryRgx.firstMatch(contentType.toString());
String boundary = boundaryMatch.group(1);
String body = await request.transform(UTF8.decoder).join();
for (String chunk in body.split(boundary)) {
var fileData = getFileDataFromChunk(
chunk, boundary, fileUploadName, result.body);
if (fileData != null)
fileData.forEach((x) => result.files.add(x));
}
}
}
return result;
}
/// Parses file data from a multipart/form-data chunk.
List<FileUploadInfo> getFileDataFromChunk(String chunk, String boundary, String fileUploadName,
Map body) {
FileUploadInfo result = new FileUploadInfo();
RegExp isFormDataRgx = new RegExp(
r'Content-Disposition:\s*([^;]+);\s*name="([^"]+)"');
if (isFormDataRgx.hasMatch(chunk)) {
Match formDataMatch = isFormDataRgx.firstMatch(chunk);
String disposition = formDataMatch.group(1);
String name = formDataMatch.group(2);
String restOfChunk = chunk.substring(formDataMatch.end);
RegExp parseFilenameRgx = new RegExp(r'filename="([^"]+)"');
if (parseFilenameRgx.hasMatch(chunk)) {
result.filename = parseFilenameRgx.firstMatch(chunk).group(1);
}
RegExp contentTypeRgx = new RegExp(r'Content-Type:\s*([^\r\n]+)\r\n');
if (contentTypeRgx.hasMatch(restOfChunk)) {
Match contentTypeMatch = contentTypeRgx.firstMatch(restOfChunk);
restOfChunk = restOfChunk.substring(contentTypeMatch.end);
result.mimeType = contentTypeMatch.group(1);
} else restOfChunk = restOfChunk.replaceAll(new RegExp(r'^(\r\n)+'), "");
restOfChunk = restOfChunk
.replaceAll(boundary, "")
.replaceFirst(new RegExp(r'\r\n$'), "");
if (disposition == 'file' && name == fileUploadName) {
result.name = name;
result.data = UTF8.encode(restOfChunk);
return [result];
} else {
buildMapFromUri(body, "$name=$restOfChunk");
return null;
}
}
return null;
}
/// Parses a URI-encoded string into real data! **Wow!**
///
/// Whichever map you provide will be automatically populated from the urlencoded body string you provide.
buildMapFromUri(Map map, String body) {
RegExp parseArrayRgx = new RegExp(r'^(.+)\[\]$');
for (String keyValuePair in body.split('&')) {
if (keyValuePair.contains('=')) {
List<String> split = keyValuePair.split('=');
String key = Uri.decodeQueryComponent(split[0]);
String value = Uri.decodeQueryComponent(split[1]);
if (parseArrayRgx.hasMatch(key)) {
Match queryMatch = parseArrayRgx.firstMatch(key);
key = queryMatch.group(1);
if (!(map[key] is List)) {
map[key] = [];
}
map[key].add(getValue(value));
} else if (key.contains('.')) {
// i.e. map.foo.bar => [map, foo, bar]
List<String> keys = key.split('.');
Map targetMap = map[keys[0]] ?? {};
map[keys[0]] = targetMap;
for (int i = 1; i < keys.length; i++) {
if (i < keys.length - 1) {
targetMap[keys[i]] = targetMap[keys[i]] ?? {};
targetMap = targetMap[keys[i]];
} else {
targetMap[keys[i]] = getValue(value);
}
}
}
else map[key] = getValue(value);
} else map[Uri.decodeQueryComponent(keyValuePair)] = true;
}
}
getValue(String value) {
num numValue = num.parse(value, (_) => double.NAN);
if (!numValue.isNaN)
return numValue;
else if (value.startsWith('[') && value.endsWith(']'))
return JSON.decode(value);
else if (value.startsWith('{') && value.endsWith('}'))
return JSON.decode(value);
else if (value.trim().toLowerCase() == 'null')
return null;
else return value;
}
export 'src/body_parser.dart';
export 'src/body_parse_result.dart';
export 'src/file_upload_info.dart';
export 'src/parse_body.dart';

View file

@ -0,0 +1,13 @@
import 'file_upload_info.dart';
/// A representation of data from an incoming request.
class BodyParseResult {
/// The parsed body.
Map body = {};
/// The parsed query string.
Map query = {};
/// All files uploaded within this request.
List<FileUploadInfo> files = [];
}

21
lib/src/body_parser.dart Normal file
View file

@ -0,0 +1,21 @@
import 'dart:async';
import 'dart:io';
import 'body_parse_result.dart';
class BodyParser implements StreamTransformer<List<int>, BodyParseResult> {
@override
Stream<BodyParseResult> bind(HttpRequest stream) {
var _stream = new StreamController<BodyParseResult>();
stream.toList().then((lists) {
var ints = [];
lists.forEach(ints.addAll);
_stream.close();
});
return _stream.stream;
}
}

8
lib/src/chunk.dart Normal file
View file

@ -0,0 +1,8 @@
import 'file_upload_info.dart';
List<FileUploadInfo> getFileDataFromChunk(String chunk, String boundary,
String fileUploadName,
Map body) {
List<FileUploadInfo> result = [];
return result;
}

View file

@ -1,5 +1,3 @@
part of body_parser;
/// Represents a file uploaded to the server.
class FileUploadInfo {
/// The MIME type of the uploaded file.

14
lib/src/get_value.dart Normal file
View file

@ -0,0 +1,14 @@
import 'dart:convert';
getValue(String value) {
num numValue = num.parse(value, (_) => double.NAN);
if (!numValue.isNaN)
return numValue;
else if (value.startsWith('[') && value.endsWith(']'))
return JSON.decode(value);
else if (value.startsWith('{') && value.endsWith('}'))
return JSON.decode(value);
else if (value.trim().toLowerCase() == 'null')
return null;
else return value;
}

41
lib/src/map_from_uri.dart Normal file
View file

@ -0,0 +1,41 @@
import 'get_value.dart';
/// Parses a URI-encoded string into real data! **Wow!**
///
/// Whichever map you provide will be automatically populated from the urlencoded body string you provide.
buildMapFromUri(Map map, String body) {
RegExp parseArrayRgx = new RegExp(r'^(.+)\[\]$');
for (String keyValuePair in body.split('&')) {
if (keyValuePair.contains('=')) {
List<String> split = keyValuePair.split('=');
String key = Uri.decodeQueryComponent(split[0]);
String value = Uri.decodeQueryComponent(split[1]);
if (parseArrayRgx.hasMatch(key)) {
Match queryMatch = parseArrayRgx.firstMatch(key);
key = queryMatch.group(1);
if (!(map[key] is List)) {
map[key] = [];
}
map[key].add(getValue(value));
} else if (key.contains('.')) {
// i.e. map.foo.bar => [map, foo, bar]
List<String> keys = key.split('.');
Map targetMap = map[keys[0]] ?? {};
map[keys[0]] = targetMap;
for (int i = 1; i < keys.length; i++) {
if (i < keys.length - 1) {
targetMap[keys[i]] = targetMap[keys[i]] ?? {};
targetMap = targetMap[keys[i]];
} else {
targetMap[keys[i]] = getValue(value);
}
}
}
else map[key] = getValue(value);
} else map[Uri.decodeQueryComponent(keyValuePair)] = true;
}
}

59
lib/src/parse_body.dart Normal file
View file

@ -0,0 +1,59 @@
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:http_server/http_server.dart';
import 'package:mime/mime.dart';
import 'body_parse_result.dart';
import 'chunk.dart';
import 'file_upload_info.dart';
import 'map_from_uri.dart';
/// Grabs data from an incoming request.
///
/// Supports URL-encoded and JSON, as well as multipart/* forms.
/// On a file upload request, only fields with the name **'file'** are processed
/// as files. Anything else is put in the body. You can change the upload file name
/// via the *fileUploadName* parameter. :)
Future<BodyParseResult> parseBody(HttpRequest request) async {
var result = new BodyParseResult();
if (request.headers.contentType != null) {
if (request.headers.contentType.primaryType == 'multipart' &&
request.headers.contentType.parameters.containsKey('boundary')) {
var parts = request
.transform(new MimeMultipartTransformer(
request.headers.contentType.parameters['boundary']))
.map((part) =>
HttpMultipartFormData.parse(part, defaultEncoding: UTF8));
await for (HttpMultipartFormData part in parts) {
if (part.isBinary || part.contentDisposition.parameters.containsKey("filename")) {
BytesBuilder builder = await part.fold(new BytesBuilder(), (BytesBuilder b, d) => b..add(d is! String ? d : d.codeUnits));
var upload = new FileUploadInfo(
mimeType: part.contentType.mimeType,
name: part.contentDisposition.parameters['name'],
filename: part.contentDisposition.parameters['filename'] ?? 'file',
data: builder.takeBytes());
result.files.add(upload);
} else if (part.isText) {
var text = await part.join();
buildMapFromUri(result.body, '${part.contentDisposition.parameters["name"]}=$text');
} else {
print("Found something else : ${part.contentDisposition}");
}
}
} else if (request.headers.contentType.mimeType ==
ContentType.JSON.mimeType) {
result.body
.addAll(JSON.decode(await request.transform(UTF8.decoder).join()));
} else if (request.headers.contentType.mimeType ==
'application/x-www-form-urlencoded') {
String body = await request.transform(UTF8.decoder).join();
buildMapFromUri(result.body, body);
}
} else if (request.uri.hasQuery) {
buildMapFromUri(result.query, request.uri.query);
}
return result;
}

View file

@ -1,9 +1,11 @@
name: body_parser
author: Tobe O <thosakwe@gmail.com>
version: 1.0.0-dev
version: 1.0.0-dev+1
description: Parse request bodies and query strings in Dart.
homepage: https://github.com/thosakwe/body_parser
dependencies:
http_server: ">=0.9.6 <1.0.0"
dev_dependencies:
http: any
json_god: any
test: any
http: ">=0.11.3 <0.12.0"
json_god: ">=2.0.0-beta <3.0.0"
test: ">=0.12.15 <0.13.0"

View file

@ -1,168 +1,9 @@
import 'dart:io';
import 'package:body_parser/body_parser.dart';
import 'package:http/http.dart' as http;
import 'package:json_god/json_god.dart';
import 'package:test/test.dart';
import 'server.dart' as server;
import 'uploads.dart' as uploads;
main() {
group('Test server support', () {
HttpServer server;
String url;
http.Client client;
God god;
setUp(() async {
server = await HttpServer.bind(InternetAddress.LOOPBACK_IP_V4, 0);
server.listen((HttpRequest request) async {
//Server will simply return a JSON representation of the parsed body
request.response.write(god.serialize(await parseBody(request)));
await request.response.close();
});
url = 'http://localhost:${server.port}';
print('Test server listening on $url');
client = new http.Client();
god = new God();
});
tearDown(() async {
await server.close(force: true);
client.close();
server = null;
url = null;
client = null;
god = null;
});
group('query string', () {
test('GET Simple', () async {
print('GET $url/?hello=world');
var response = await client.get('$url/?hello=world');
print('Response: ${response.body}');
expect(response.body,
equals('{"body":{},"query":{"hello":"world"},"files":[]}'));
});
test('GET Complex', () async {
var postData = 'hello=world&nums%5B%5D=1&nums%5B%5D=2.0&nums%5B%5D=${3 -
1}&map.foo.bar=baz';
print('Body: $postData');
var response = await client.get('$url/?$postData');
print('Response: ${response.body}');
var query = god.deserialize(response.body)['query'];
expect(query['hello'], equals('world'));
expect(query['nums'][2], equals(2));
expect(query['map'] is Map, equals(true));
expect(query['map']['foo'], equals({'bar': 'baz'}));
});
});
group('urlencoded', () {
Map<String, String> headers = {
HttpHeaders.CONTENT_TYPE: 'application/x-www-form-urlencoded'
};
test('POST Simple', () async {
print('Body: hello=world');
var response = await client.post(
url, headers: headers, body: 'hello=world');
print('Response: ${response.body}');
expect(response.body,
equals('{"body":{"hello":"world"},"query":{},"files":[]}'));
});
test('Post Complex', () async {
var postData = 'hello=world&nums%5B%5D=1&nums%5B%5D=2.0&nums%5B%5D=${3 -
1}&map.foo.bar=baz';
var response = await client.post(url, headers: headers, body: postData);
var body = god.deserialize(response.body)['body'];
expect(body['hello'], equals('world'));
expect(body['nums'][2], equals(2));
expect(body['map'] is Map, equals(true));
expect(body['map']['foo'], equals({'bar': 'baz'}));
});
});
group('JSON', () {
Map<String, String> headers = {
HttpHeaders.CONTENT_TYPE: ContentType.JSON.toString()
};
test('Post Simple', () async {
var postData = god.serialize({
'hello': 'world'
});
print('Body: $postData');
var response = await client.post(
url, headers: headers, body: postData);
print('Response: ${response.body}');
expect(response.body,
equals('{"body":{"hello":"world"},"query":{},"files":[]}'));
});
test('Post Complex', () async {
var postData = god.serialize({
'hello': 'world',
'nums': [1, 2.0, 3 - 1],
'map': {
'foo': {
'bar': 'baz'
}
}
});
print('Body: $postData');
var response = await client.post(url, headers: headers, body: postData);
print('Response: ${response.body}');
var body = god.deserialize(response.body)['body'];
expect(body['hello'], equals('world'));
expect(body['nums'][2], equals(2));
expect(body['map'] is Map, equals(true));
expect(body['map']['foo'], equals({'bar': 'baz'}));
});
});
group('File', () {
test('Single upload', () async {
String boundary = '----myBoundary';
Map headers = {
HttpHeaders.CONTENT_TYPE: 'multipart/form-data; boundary=$boundary'
};
String postData = '\r\n$boundary\r\n' +
'Content-Disposition: form-data; name="hello"\r\nworld\r\n$boundary\r\n' +
'Content-Disposition: file; name="file"; filename="app.dart"\r\n' +
'Content-Type: text/plain\r\nHello world\r\n$boundary--';
print('Form Data: \n$postData');
var response = await client.post(url, headers: headers, body: postData);
print('Response: ${response.body}');
Map json = god.deserialize(response.body);
List<Map> files = json['files'];
expect(files.length, equals(1));
expect(files[0]['name'], equals('file'));
expect(files[0]['mimeType'], equals('text/plain'));
expect(files[0]['data'].length, equals(11));
expect(files[0]['filename'], equals('app.dart'));
expect(json['body']['hello'], equals('world'));
});
test('Multiple upload', () async {
String boundary = '----myBoundary';
Map headers = {
HttpHeaders.CONTENT_TYPE: 'multipart/form-data; boundary=$boundary'
};
String postData = '\r\n$boundary\r\n' +
'Content-Disposition: form-data; name="json"\r\ngod\r\n$boundary\r\n' +
'Content-Disposition: file; name="file"; filename="app.dart"\r\n' +
'Content-Type: text/plain\r\nHello world\r\n$boundary--';
print('Form Data: \n$postData');
var response = await client.post(url, headers: headers, body: postData);
print('Response: ${response.body}');
Map json = god.deserialize(response.body);
List<Map> files = json['files'];
expect(files.length, equals(1));
expect(files[0]['name'], equals('file'));
expect(files[0]['mimeType'], equals('text/plain'));
expect(files[0]['data'].length, equals(11));
expect(json['body']['json'], equals('god'));
}, skip: 'Multiple file uploads are yet to come.');
});
});
}
group('server', server.main);
group('uploads', uploads.main);
}

110
test/server.dart Normal file
View file

@ -0,0 +1,110 @@
import 'dart:io';
import 'package:body_parser/body_parser.dart';
import 'package:http/http.dart' as http;
import 'package:json_god/json_god.dart' as god;
import 'package:test/test.dart';
main() {
HttpServer server;
String url;
http.Client client;
setUp(() async {
server = await HttpServer.bind(InternetAddress.LOOPBACK_IP_V4, 0);
server.listen((HttpRequest request) async {
//Server will simply return a JSON representation of the parsed body
request.response.write(god.serialize(await parseBody(request)));
await request.response.close();
});
url = 'http://localhost:${server.port}';
print('Test server listening on $url');
client = new http.Client();
});
tearDown(() async {
await server.close(force: true);
client.close();
server = null;
url = null;
client = null;
});
group('query string', () {
test('GET Simple', () async {
print('GET $url/?hello=world');
var response = await client.get('$url/?hello=world');
print('Response: ${response.body}');
expect(response.body,
equals('{"body":{},"query":{"hello":"world"},"files":[]}'));
});
test('GET Complex', () async {
var postData = 'hello=world&nums%5B%5D=1&nums%5B%5D=2.0&nums%5B%5D=${3 -
1}&map.foo.bar=baz';
print('Body: $postData');
var response = await client.get('$url/?$postData');
print('Response: ${response.body}');
var query = god.deserialize(response.body)['query'];
expect(query['hello'], equals('world'));
expect(query['nums'][2], equals(2));
expect(query['map'] is Map, equals(true));
expect(query['map']['foo'], equals({'bar': 'baz'}));
});
});
group('urlencoded', () {
Map<String, String> headers = {
HttpHeaders.CONTENT_TYPE: 'application/x-www-form-urlencoded'
};
test('POST Simple', () async {
print('Body: hello=world');
var response =
await client.post(url, headers: headers, body: 'hello=world');
print('Response: ${response.body}');
expect(response.body,
equals('{"body":{"hello":"world"},"query":{},"files":[]}'));
});
test('Post Complex', () async {
var postData = 'hello=world&nums%5B%5D=1&nums%5B%5D=2.0&nums%5B%5D=${3 -
1}&map.foo.bar=baz';
var response = await client.post(url, headers: headers, body: postData);
var body = god.deserialize(response.body)['body'];
expect(body['hello'], equals('world'));
expect(body['nums'][2], equals(2));
expect(body['map'] is Map, equals(true));
expect(body['map']['foo'], equals({'bar': 'baz'}));
});
});
group('JSON', () {
Map<String, String> headers = {
HttpHeaders.CONTENT_TYPE: ContentType.JSON.toString()
};
test('Post Simple', () async {
var postData = god.serialize({'hello': 'world'});
print('Body: $postData');
var response = await client.post(url, headers: headers, body: postData);
print('Response: ${response.body}');
expect(response.body,
equals('{"body":{"hello":"world"},"query":{},"files":[]}'));
});
test('Post Complex', () async {
var postData = god.serialize({
'hello': 'world',
'nums': [1, 2.0, 3 - 1],
'map': {
'foo': {'bar': 'baz'}
}
});
print('Body: $postData');
var response = await client.post(url, headers: headers, body: postData);
print('Response: ${response.body}');
var body = god.deserialize(response.body)['body'];
expect(body['hello'], equals('world'));
expect(body['nums'][2], equals(2));
expect(body['map'] is Map, equals(true));
expect(body['map']['foo'], equals({'bar': 'baz'}));
});
});
}

135
test/uploads.dart Normal file
View file

@ -0,0 +1,135 @@
import 'dart:io';
import 'package:body_parser/body_parser.dart';
import 'package:http/http.dart' as http;
import 'package:json_god/json_god.dart' as god;
import 'package:test/test.dart';
main() {
HttpServer server;
String url;
http.Client client;
setUp(() async {
server = await HttpServer.bind(InternetAddress.LOOPBACK_IP_V4, 0);
server.listen((HttpRequest request) async {
//Server will simply return a JSON representation of the parsed body
request.response.write(god.serialize(await parseBody(request)));
await request.response.close();
});
url = 'http://localhost:${server.port}';
print('Test server listening on $url');
client = new http.Client();
});
tearDown(() async {
await server.close(force: true);
client.close();
server = null;
url = null;
client = null;
});
test('No upload', () async {
String boundary = 'myBoundary';
Map headers = {
HttpHeaders.CONTENT_TYPE: 'multipart/form-data; boundary=$boundary'
};
String postData = '''
--$boundary
Content-Disposition: form-data; name="hello"
world
--$boundary--
'''
.replaceAll("\n", "\r\n");
print(
'Form Data: \n${postData.replaceAll("\r", "\\r").replaceAll("\n", "\\n")}');
var response = await client.post(url, headers: headers, body: postData);
print('Response: ${response.body}');
Map json = god.deserialize(response.body);
List<Map> files = json['files'];
expect(files.length, equals(0));
expect(json['body']['hello'], equals('world'));
});
test('Single upload', () async {
String boundary = 'myBoundary';
Map headers = {
HttpHeaders.CONTENT_TYPE: new ContentType("multipart", "form-data",
parameters: {"boundary": boundary}).toString()
};
String postData = '''
--$boundary
Content-Disposition: form-data; name="hello"
world
--$boundary
Content-Disposition: form-data; name="file"; filename="app.dart"
Content-Type: application/dart
Hello world
--$boundary--
'''
.replaceAll("\n", "\r\n");
print(
'Form Data: \n${postData.replaceAll("\r", "\\r").replaceAll("\n", "\\n")}');
var response = await client.post(url, headers: headers, body: postData);
print('Response: ${response.body}');
Map json = god.deserialize(response.body);
List<Map> files = json['files'];
expect(files.length, equals(1));
expect(files[0]['name'], equals('file'));
expect(files[0]['mimeType'], equals('application/dart'));
expect(files[0]['data'].length, equals(11));
expect(files[0]['filename'], equals('app.dart'));
expect(json['body']['hello'], equals('world'));
});
test('Multiple upload', () async {
String boundary = 'myBoundary';
Map headers = {
HttpHeaders.CONTENT_TYPE: 'multipart/form-data; boundary=$boundary'
};
String postData = '''
--$boundary
Content-Disposition: form-data; name="json"
god
--$boundary
Content-Disposition: form-data; name="num"
14.50000
--$boundary
Content-Disposition: form-data; name="file"; filename="app.dart"
Content-Type: text/plain
Hello world
--$boundary
Content-Disposition: form-data; name="entry-point"; filename="main.js"
Content-Type: text/javascript
function main() {
console.log("Hello, world!");
}
--$boundary--
'''
.replaceAll("\n", "\r\n");
print(
'Form Data: \n${postData.replaceAll("\r", "\\r").replaceAll("\n", "\\n")}');
var response = await client.post(url, headers: headers, body: postData);
print('Response: ${response.body}');
Map json = god.deserialize(response.body);
List<Map> files = json['files'];
expect(files.length, equals(2));
expect(files[0]['name'], equals('file'));
expect(files[0]['mimeType'], equals('text/plain'));
expect(files[0]['data'].length, equals(11));
expect(files[1]['name'], equals('entry-point'));
expect(files[1]['mimeType'], equals('text/javascript'));
expect(json['body']['json'], equals('god'));
expect(json['body']['num'], equals(14.5));
});
}