From fad5c0049df278cc498b6cdb519b09e845a070a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Hoguin?= Date: Wed, 21 Aug 2013 20:40:02 +0200 Subject: Initial commit with most of spdy/3 --- LICENSE | 13 +++ Makefile | 5 + README.md | 20 ++++ erlang.mk | 224 +++++++++++++++++++++++++++++++++++++++++++++ src/cow_spdy.erl | 264 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/cow_spdy.hrl | 181 ++++++++++++++++++++++++++++++++++++ src/cowlib.app.src | 24 +++++ 7 files changed, 731 insertions(+) create mode 100644 LICENSE create mode 100644 Makefile create mode 100644 README.md create mode 100644 erlang.mk create mode 100644 src/cow_spdy.erl create mode 100644 src/cow_spdy.hrl create mode 100644 src/cowlib.app.src diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..3e227ee --- /dev/null +++ b/LICENSE @@ -0,0 +1,13 @@ +Copyright (c) 2013, Loïc Hoguin + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..3b44c01 --- /dev/null +++ b/Makefile @@ -0,0 +1,5 @@ +# See LICENSE for licensing information. + +PROJECT = cowlib + +include erlang.mk diff --git a/README.md b/README.md new file mode 100644 index 0000000..9523836 --- /dev/null +++ b/README.md @@ -0,0 +1,20 @@ +Cowlib +====== + +Cowlib is a support library for manipulating Web protocols. + +Goals +----- + +Cowlib provides libraries for parsing and building messages +for various Web protocols, including SPDY, HTTP and Websocket. + +It is optimized for completeness rather than speed. No value +is ignored, they are all returned. + +Support +------- + + * Official IRC Channel: #ninenines on irc.freenode.net + * [Mailing Lists](http://lists.ninenines.eu) + * [Commercial Support](http://ninenines.eu/support) diff --git a/erlang.mk b/erlang.mk new file mode 100644 index 0000000..f073155 --- /dev/null +++ b/erlang.mk @@ -0,0 +1,224 @@ +# Copyright (c) 2013, Loïc Hoguin +# +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +# Project. + +PROJECT ?= $(notdir $(CURDIR)) + +# Packages database file. + +PKG_FILE ?= $(CURDIR)/.erlang.mk.packages.v1 +export PKG_FILE + +PKG_FILE_URL ?= https://raw.github.com/extend/erlang.mk/master/packages.v1.txt + +define get_pkg_file + wget -O $(PKG_FILE) $(PKG_FILE_URL) +endef + +# Verbosity and tweaks. + +V ?= 0 + +appsrc_verbose_0 = @echo " APP " $(PROJECT).app.src; +appsrc_verbose = $(appsrc_verbose_$(V)) + +erlc_verbose_0 = @echo " ERLC " $(filter %.erl %.core,$(?F)); +erlc_verbose = $(erlc_verbose_$(V)) + +xyrl_verbose_0 = @echo " XYRL " $(filter %.xrl %.yrl,$(?F)); +xyrl_verbose = $(xyrl_verbose_$(V)) + +dtl_verbose_0 = @echo " DTL " $(filter %.dtl,$(?F)); +dtl_verbose = $(dtl_verbose_$(V)) + +gen_verbose_0 = @echo " GEN " $@; +gen_verbose = $(gen_verbose_$(V)) + +.PHONY: all clean-all app clean deps clean-deps docs clean-docs \ + build-tests tests build-plt dialyze + +# Deps directory. + +DEPS_DIR ?= $(CURDIR)/deps +export DEPS_DIR + +REBAR_DEPS_DIR = $(DEPS_DIR) +export REBAR_DEPS_DIR + +ALL_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(DEPS)) +ALL_TEST_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(TEST_DEPS)) + +# Application. + +ERLC_OPTS ?= -Werror +debug_info +warn_export_all +warn_export_vars \ + +warn_shadow_vars +warn_obsolete_guard # +bin_opt_info +warn_missing_spec +COMPILE_FIRST ?= +COMPILE_FIRST_PATHS = $(addprefix src/,$(addsuffix .erl,$(COMPILE_FIRST))) + +all: deps app + +clean-all: clean clean-deps clean-docs + $(gen_verbose) rm -rf .$(PROJECT).plt $(DEPS_DIR) logs + +app: ebin/$(PROJECT).app + $(eval MODULES := $(shell find ebin -name \*.beam \ + | sed 's/ebin\///;s/\.beam/,/' | sed '$$s/.$$//')) + $(appsrc_verbose) cat src/$(PROJECT).app.src \ + | sed 's/{modules, \[\]}/{modules, \[$(MODULES)\]}/' \ + > ebin/$(PROJECT).app + +define compile_erl + $(erlc_verbose) ERL_LIBS=$(DEPS_DIR) erlc -v $(ERLC_OPTS) -o ebin/ \ + -pa ebin/ -I include/ $(COMPILE_FIRST_PATHS) $(1) +endef + +define compile_xyrl + $(xyrl_verbose) erlc -v -o ebin/ $(1) + $(xyrl_verbose) erlc $(ERLC_OPTS) -o ebin/ ebin/*.erl + @rm ebin/*.erl +endef + +define compile_dtl + $(dtl_verbose) erl -noshell -pa ebin/ $(DEPS_DIR)/erlydtl/ebin/ -eval ' \ + Compile = fun(F) -> \ + Module = list_to_atom( \ + string:to_lower(filename:basename(F, ".dtl")) ++ "_dtl"), \ + erlydtl_compiler:compile(F, Module, [{out_dir, "ebin/"}]) \ + end, \ + _ = [Compile(F) || F <- string:tokens("$(1)", " ")], \ + init:stop()' +endef + +ebin/$(PROJECT).app: src/*.erl $(wildcard src/*.core) \ + $(wildcard src/*.xrl) $(wildcard src/*.yrl) \ + $(wildcard templates/*.dtl) + @mkdir -p ebin/ + $(if $(strip $(filter %.erl %.core,$?)), \ + $(call compile_erl,$(filter %.erl %.core,$?))) + $(if $(strip $(filter %.xrl %.yrl,$?)), \ + $(call compile_xyrl,$(filter %.xrl %.yrl,$?))) + $(if $(strip $(filter %.dtl,$?)), \ + $(call compile_dtl,$(filter %.dtl,$?))) + +clean: + $(gen_verbose) rm -rf ebin/ test/*.beam erl_crash.dump + +# Dependencies. + +define get_dep + @mkdir -p $(DEPS_DIR) +ifeq (,$(findstring pkg://,$(word 1,$(dep_$(1))))) + git clone -n -- $(word 1,$(dep_$(1))) $(DEPS_DIR)/$(1) +else + @if [ ! -f $(PKG_FILE) ]; then $(call get_pkg_file); fi + git clone -n -- `awk 'BEGIN { FS = "\t" }; \ + $$$$1 == "$(subst pkg://,,$(word 1,$(dep_$(1))))" { print $$$$2 }' \ + $(PKG_FILE)` $(DEPS_DIR)/$(1) +endif + cd $(DEPS_DIR)/$(1) ; git checkout -q $(word 2,$(dep_$(1))) +endef + +define dep_target +$(DEPS_DIR)/$(1): + $(call get_dep,$(1)) +endef + +$(foreach dep,$(DEPS),$(eval $(call dep_target,$(dep)))) + +deps: $(ALL_DEPS_DIRS) + @for dep in $(ALL_DEPS_DIRS) ; do \ + if [ -f $$dep/Makefile ] ; then \ + $(MAKE) -C $$dep ; \ + else \ + echo "include $(CURDIR)/erlang.mk" | $(MAKE) -f - -C $$dep ; \ + fi ; \ + done + +clean-deps: + @for dep in $(ALL_DEPS_DIRS) ; do $(MAKE) -C $$dep clean; done + +# Documentation. + +docs: clean-docs + $(gen_verbose) erl -noshell \ + -eval 'edoc:application($(PROJECT), ".", []), init:stop().' + +clean-docs: + $(gen_verbose) rm -f doc/*.css doc/*.html doc/*.png doc/edoc-info + +# Tests. + +$(foreach dep,$(TEST_DEPS),$(eval $(call dep_target,$(dep)))) + +build-test-deps: $(ALL_TEST_DEPS_DIRS) + @for dep in $(ALL_TEST_DEPS_DIRS) ; do $(MAKE) -C $$dep; done + +build-tests: build-test-deps + $(gen_verbose) ERL_LIBS=$(DEPS_DIR) erlc -v $(ERLC_OPTS) -o test/ \ + $(wildcard test/*.erl test/*/*.erl) -pa ebin/ + +CT_RUN = ct_run \ + -no_auto_compile \ + -noshell \ + -pa ebin $(DEPS_DIR)/*/ebin \ + -dir test \ + -logdir logs +# -cover test/cover.spec + +CT_SUITES ?= +CT_SUITES_FULL = $(addsuffix _SUITE,$(CT_SUITES)) + +tests: ERLC_OPTS += -DTEST=1 +'{parse_transform, eunit_autoexport}' +tests: clean deps app build-tests + @mkdir -p logs/ + @$(CT_RUN) -suite $(CT_SUITES_FULL) + $(gen_verbose) rm -f test/*.beam + +# Dialyzer. + +PLT_APPS ?= +DIALYZER_OPTS ?= -Werror_handling -Wrace_conditions \ + -Wunmatched_returns # -Wunderspecs + +build-plt: deps app + @dialyzer --build_plt --output_plt .$(PROJECT).plt \ + --apps erts kernel stdlib $(PLT_APPS) $(ALL_DEPS_DIRS) + +dialyze: + @dialyzer --src src --plt .$(PROJECT).plt --no_native $(DIALYZER_OPTS) + +# Packages. + +$(PKG_FILE): + @$(call get_pkg_file) + +pkg-list: $(PKG_FILE) + @cat $(PKG_FILE) | awk 'BEGIN { FS = "\t" }; { print \ + "Name:\t\t" $$1 "\n" \ + "Repository:\t" $$2 "\n" \ + "Website:\t" $$3 "\n" \ + "Description:\t" $$4 "\n" }' + +ifdef q +pkg-search: $(PKG_FILE) + @cat $(PKG_FILE) | grep -i ${q} | awk 'BEGIN { FS = "\t" }; { print \ + "Name:\t\t" $$1 "\n" \ + "Repository:\t" $$2 "\n" \ + "Website:\t" $$3 "\n" \ + "Description:\t" $$4 "\n" }' +else +pkg-search: + @echo "Usage: make pkg-search q=STRING" +endif diff --git a/src/cow_spdy.erl b/src/cow_spdy.erl new file mode 100644 index 0000000..4856afd --- /dev/null +++ b/src/cow_spdy.erl @@ -0,0 +1,264 @@ +%% Copyright (c) 2013, Loïc Hoguin +%% +%% Permission to use, copy, modify, and/or distribute this software for any +%% purpose with or without fee is hereby granted, provided that the above +%% copyright notice and this permission notice appear in all copies. +%% +%% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +%% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +%% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +%% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +%% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +%% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +%% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +-module(cow_spdy). + +%% Zstream. +-export([deflate_init/0]). +-export([inflate_init/0]). + +%% Parse. +-export([split/1]). +-export([parse/2]). + +%% Build. +-export([data/3]). +-export([syn_stream/12]). +-export([syn_reply/6]). +-export([rst_stream/2]). +%% @todo settings +-export([ping/1]). +-export([goaway/2]). +%% @todo headers +%% @todo window_update + +-include("cow_spdy.hrl"). + +%% Zstream. + +deflate_init() -> + Zdef = zlib:open(), + ok = zlib:deflateInit(Zdef), + _ = zlib:deflateSetDictionary(Zdef, ?ZDICT), + Zdef. + +inflate_init() -> + Zinf = zlib:open(), + ok = zlib:inflateInit(Zinf), + Zinf. + +%% Parse. + +split(Data = << _:40, Length:24, _/bits >>) + when byte_size(Data) >= Length + 8 -> + Length2 = Length + 8, + << Frame:Length2/binary, Rest/bits >> = Data, + {true, Frame, Rest}; +split(Data) -> + {false, Data}. + +parse(<< 0:1, StreamID:31, 0:7, IsFinFlag:1, _:24, Data/bits >>, _) -> + {data, StreamID, from_flag(IsFinFlag), Data}; +parse(<< 1:1, 3:15, 1:16, 0:6, IsUnidirectionalFlag:1, IsFinFlag:1, + _:25, StreamID:31, _:1, AssocToStreamID:31, Priority:3, _:5, + 0:8, Rest/bits >>, Zinf) -> + case parse_headers(Rest, Zinf) of + {ok, Headers, [{<<":host">>, Host}, {<<":method">>, Method}, + {<<":path">>, Path}, {<<":scheme">>, Scheme}, + {<<":version">>, Version}]} -> + {syn_stream, StreamID, AssocToStreamID, from_flag(IsFinFlag), + from_flag(IsUnidirectionalFlag), Priority, Method, + Scheme, Host, Path, Version, Headers}; + _ -> + {error, badprotocol} + end; +parse(<< 1:1, 3:15, 2:16, 0:7, IsFinFlag:1, _:25, + StreamID:31, Rest/bits >>, Zinf) -> + case parse_headers(Rest, Zinf) of + {ok, Headers, [{<<":status">>, Status}, {<<":version">>, Version}]} -> + {syn_reply, StreamID, from_flag(IsFinFlag), + Status, Version, Headers}; + _ -> + {error, badprotocol} + end; +parse(<< 1:1, 3:15, 3:16, 0:8, _:56, StatusCode:32 >>, _) + when StatusCode =:= 0; StatusCode > 11 -> + {error, badprotocol}; +parse(<< 1:1, 3:15, 3:16, 0:8, _:25, StreamID:31, StatusCode:32 >>, _) -> + Status = case StatusCode of + 1 -> protocol_error; + 2 -> invalid_stream; + 3 -> refused_stream; + 4 -> unsupported_version; + 5 -> cancel; + 6 -> internal_error; + 7 -> flow_control_error; + 8 -> stream_in_use; + 9 -> stream_already_closed; + 10 -> invalid_credentials; + 11 -> frame_too_large + end, + {rst_stream, StreamID, Status}; +parse(<< 1:1, 3:15, 4:16, 0:7, ClearSettingsFlag:1, _:24, + NbEntries:32, Rest/bits >>, _) -> + try + Settings = [begin + Is0 = 0, + Key = case ID of + 1 -> upload_bandwidth; + 2 -> download_bandwidth; + 3 -> round_trip_time; + 4 -> max_concurrent_streams; + 5 -> current_cwnd; + 6 -> download_retrans_rate; + 7 -> initial_window_size; + 8 -> client_certificate_vector_size + end, + {Key, Value, from_flag(PersistFlag), from_flag(WasPersistedFlag)} + end || << Is0:6, WasPersistedFlag:1, PersistFlag:1, + ID:24, Value:32 >> <= Rest], + NbEntries = length(Settings), + {settings, from_flag(ClearSettingsFlag), Settings} + catch _:_ -> + {error, badprotocol} + end; +parse(<< 1:1, 3:15, 6:16, 0:8, _:24, PingID:32 >>, _) -> + {ping, PingID}; +parse(<< 1:1, 3:15, 7:16, 0:8, _:56, StatusCode:32 >>, _) + when StatusCode > 2 -> + {error, badprotocol}; +parse(<< 1:1, 3:15, 7:16, 0:8, _:25, LastGoodStreamID:31, + StatusCode:32 >>, _) -> + Status = case StatusCode of + 0 -> ok; + 1 -> protocol_error; + 2 -> internal_error + end, + {goaway, LastGoodStreamID, Status}; +parse(<< 1:1, 3:15, 8:16, 0:7, IsFinFlag:1, _:25, StreamID:31, + Rest/bits >>, Zinf) -> + case parse_headers(Rest, Zinf) of + {ok, Headers, []} -> + {headers, StreamID, from_flag(IsFinFlag), Headers}; + _ -> + {error, badprotocol} + end; +parse(<< 1:1, 3:15, 9:16, 0:8, _:57, 0:31 >>, _) -> + {error, badprotocol}; +parse(<< 1:1, 3:15, 9:16, 0:8, _:25, StreamID:31, + _:1, DeltaWindowSize:31 >>, _) -> + {window_update, StreamID, DeltaWindowSize}; +parse(_, _) -> + {error, badprotocol}. + +parse_headers(Data, Zinf) -> + [<< NbHeaders:32, Rest/bits >>] = inflate(Zinf, Data), + parse_headers(Rest, NbHeaders, [], []). + +parse_headers(<<>>, 0, Headers, SpHeaders) -> + {ok, lists:reverse(Headers), lists:sort(SpHeaders)}; +parse_headers(<<>>, _, _, _) -> + error; +parse_headers(_, 0, _, _) -> + error; +parse_headers(<< 0:32, _/bits >>, _, _, _) -> + error; +parse_headers(<< L1:32, Key:L1/binary, L2:32, Value:L2/binary, Rest/bits >>, + NbHeaders, Acc, SpAcc) -> + case Key of + << $:, _/bits >> -> + parse_headers(Rest, NbHeaders - 1, Acc, [{Key, Value}|SpAcc]); + _ -> + parse_headers(Rest, NbHeaders - 1, [{Key, Value}|Acc], SpAcc) + end. + +inflate(Zinf, Data) -> + try + zlib:inflate(Zinf, Data) + catch _:_ -> + ok = zlib:inflateSetDictionary(Zinf, ?ZDICT), + zlib:inflate(Zinf, <<>>) + end. + +from_flag(0) -> false; +from_flag(1) -> true. + +%% Build. + +data(StreamID, IsFin, Data) -> + IsFinFlag = to_flag(IsFin), + Length = iolist_size(Data), + [<< 0:1, StreamID:31, 0:7, IsFinFlag:1, Length:24 >>, Data]. + +syn_stream(Zdef, StreamID, AssocToStreamID, IsFin, IsUnidirectional, + Priority, Method, Scheme, Host, Path, Version, Headers) -> + IsFinFlag = to_flag(IsFin), + IsUnidirectionalFlag = to_flag(IsUnidirectional), + HeaderBlock = build_headers(Zdef, [ + {<<":method">>, Method}, + {<<":scheme">>, Scheme}, + {<<":host">>, Host}, + {<<":path">>, Path}, + {<<":version">>, Version} + |Headers]), + Length = 10 + iolist_size(HeaderBlock), + [<< 1:1, 3:15, 1:16, 0:6, IsUnidirectionalFlag:1, IsFinFlag:1, + Length:24, 0:1, StreamID:31, 0:1, AssocToStreamID:31, + Priority:3, 0:5, 0:8 >>, HeaderBlock]. + +syn_reply(Zdef, StreamID, IsFin, Status, Version, Headers) -> + IsFinFlag = to_flag(IsFin), + HeaderBlock = build_headers(Zdef, [ + {<<":status">>, Status}, + {<<":version">>, Version} + |Headers]), + Length = 4 + iolist_size(HeaderBlock), + [<< 1:1, 3:15, 2:16, 0:7, IsFinFlag:1, Length:24, + 0:1, StreamID:31 >>, HeaderBlock]. + +rst_stream(StreamID, Status) -> + StatusCode = case Status of + protocol_error -> 1; + invalid_stream -> 2; + refused_stream -> 3; + unsupported_version -> 4; + cancel -> 5; + internal_error -> 6; + flow_control_error -> 7; + stream_in_use -> 8; + stream_already_closed -> 9; + invalid_credentials -> 10; + frame_too_large -> 11 + end, + << 1:1, 3:15, 3:16, 0:8, 8:24, + 0:1, StreamID:31, StatusCode:32 >>. + +%% @todo settings + +ping(PingID) -> + << 1:1, 3:15, 6:16, 0:8, 4:24, PingID:32 >>. + +goaway(LastGoodStreamID, Status) -> + StatusCode = case Status of + ok -> 0; + protocol_error -> 1; + internal_error -> 2 + end, + << 1:1, 3:15, 7:16, 0:8, 8:24, + 0:1, LastGoodStreamID:31, StatusCode:32 >>. + +%% @todo headers +%% @todo window_update + +build_headers(Zdef, Headers) -> + NbHeaders = length(Headers), + Headers2 = [begin + L1 = iolist_size(Key), + L2 = iolist_size(Value), + [<< L1:32 >>, Key, << L2:32 >>, Value] + end || {Key, Value} <- Headers], + zlib:deflate(Zdef, [<< NbHeaders:32 >>, Headers2], full). + +to_flag(false) -> 0; +to_flag(true) -> 1. diff --git a/src/cow_spdy.hrl b/src/cow_spdy.hrl new file mode 100644 index 0000000..9637b1c --- /dev/null +++ b/src/cow_spdy.hrl @@ -0,0 +1,181 @@ +%% Zlib dictionary. + +-define(ZDICT, << + 16#00, 16#00, 16#00, 16#07, 16#6f, 16#70, 16#74, 16#69, + 16#6f, 16#6e, 16#73, 16#00, 16#00, 16#00, 16#04, 16#68, + 16#65, 16#61, 16#64, 16#00, 16#00, 16#00, 16#04, 16#70, + 16#6f, 16#73, 16#74, 16#00, 16#00, 16#00, 16#03, 16#70, + 16#75, 16#74, 16#00, 16#00, 16#00, 16#06, 16#64, 16#65, + 16#6c, 16#65, 16#74, 16#65, 16#00, 16#00, 16#00, 16#05, + 16#74, 16#72, 16#61, 16#63, 16#65, 16#00, 16#00, 16#00, + 16#06, 16#61, 16#63, 16#63, 16#65, 16#70, 16#74, 16#00, + 16#00, 16#00, 16#0e, 16#61, 16#63, 16#63, 16#65, 16#70, + 16#74, 16#2d, 16#63, 16#68, 16#61, 16#72, 16#73, 16#65, + 16#74, 16#00, 16#00, 16#00, 16#0f, 16#61, 16#63, 16#63, + 16#65, 16#70, 16#74, 16#2d, 16#65, 16#6e, 16#63, 16#6f, + 16#64, 16#69, 16#6e, 16#67, 16#00, 16#00, 16#00, 16#0f, + 16#61, 16#63, 16#63, 16#65, 16#70, 16#74, 16#2d, 16#6c, + 16#61, 16#6e, 16#67, 16#75, 16#61, 16#67, 16#65, 16#00, + 16#00, 16#00, 16#0d, 16#61, 16#63, 16#63, 16#65, 16#70, + 16#74, 16#2d, 16#72, 16#61, 16#6e, 16#67, 16#65, 16#73, + 16#00, 16#00, 16#00, 16#03, 16#61, 16#67, 16#65, 16#00, + 16#00, 16#00, 16#05, 16#61, 16#6c, 16#6c, 16#6f, 16#77, + 16#00, 16#00, 16#00, 16#0d, 16#61, 16#75, 16#74, 16#68, + 16#6f, 16#72, 16#69, 16#7a, 16#61, 16#74, 16#69, 16#6f, + 16#6e, 16#00, 16#00, 16#00, 16#0d, 16#63, 16#61, 16#63, + 16#68, 16#65, 16#2d, 16#63, 16#6f, 16#6e, 16#74, 16#72, + 16#6f, 16#6c, 16#00, 16#00, 16#00, 16#0a, 16#63, 16#6f, + 16#6e, 16#6e, 16#65, 16#63, 16#74, 16#69, 16#6f, 16#6e, + 16#00, 16#00, 16#00, 16#0c, 16#63, 16#6f, 16#6e, 16#74, + 16#65, 16#6e, 16#74, 16#2d, 16#62, 16#61, 16#73, 16#65, + 16#00, 16#00, 16#00, 16#10, 16#63, 16#6f, 16#6e, 16#74, + 16#65, 16#6e, 16#74, 16#2d, 16#65, 16#6e, 16#63, 16#6f, + 16#64, 16#69, 16#6e, 16#67, 16#00, 16#00, 16#00, 16#10, + 16#63, 16#6f, 16#6e, 16#74, 16#65, 16#6e, 16#74, 16#2d, + 16#6c, 16#61, 16#6e, 16#67, 16#75, 16#61, 16#67, 16#65, + 16#00, 16#00, 16#00, 16#0e, 16#63, 16#6f, 16#6e, 16#74, + 16#65, 16#6e, 16#74, 16#2d, 16#6c, 16#65, 16#6e, 16#67, + 16#74, 16#68, 16#00, 16#00, 16#00, 16#10, 16#63, 16#6f, + 16#6e, 16#74, 16#65, 16#6e, 16#74, 16#2d, 16#6c, 16#6f, + 16#63, 16#61, 16#74, 16#69, 16#6f, 16#6e, 16#00, 16#00, + 16#00, 16#0b, 16#63, 16#6f, 16#6e, 16#74, 16#65, 16#6e, + 16#74, 16#2d, 16#6d, 16#64, 16#35, 16#00, 16#00, 16#00, + 16#0d, 16#63, 16#6f, 16#6e, 16#74, 16#65, 16#6e, 16#74, + 16#2d, 16#72, 16#61, 16#6e, 16#67, 16#65, 16#00, 16#00, + 16#00, 16#0c, 16#63, 16#6f, 16#6e, 16#74, 16#65, 16#6e, + 16#74, 16#2d, 16#74, 16#79, 16#70, 16#65, 16#00, 16#00, + 16#00, 16#04, 16#64, 16#61, 16#74, 16#65, 16#00, 16#00, + 16#00, 16#04, 16#65, 16#74, 16#61, 16#67, 16#00, 16#00, + 16#00, 16#06, 16#65, 16#78, 16#70, 16#65, 16#63, 16#74, + 16#00, 16#00, 16#00, 16#07, 16#65, 16#78, 16#70, 16#69, + 16#72, 16#65, 16#73, 16#00, 16#00, 16#00, 16#04, 16#66, + 16#72, 16#6f, 16#6d, 16#00, 16#00, 16#00, 16#04, 16#68, + 16#6f, 16#73, 16#74, 16#00, 16#00, 16#00, 16#08, 16#69, + 16#66, 16#2d, 16#6d, 16#61, 16#74, 16#63, 16#68, 16#00, + 16#00, 16#00, 16#11, 16#69, 16#66, 16#2d, 16#6d, 16#6f, + 16#64, 16#69, 16#66, 16#69, 16#65, 16#64, 16#2d, 16#73, + 16#69, 16#6e, 16#63, 16#65, 16#00, 16#00, 16#00, 16#0d, + 16#69, 16#66, 16#2d, 16#6e, 16#6f, 16#6e, 16#65, 16#2d, + 16#6d, 16#61, 16#74, 16#63, 16#68, 16#00, 16#00, 16#00, + 16#08, 16#69, 16#66, 16#2d, 16#72, 16#61, 16#6e, 16#67, + 16#65, 16#00, 16#00, 16#00, 16#13, 16#69, 16#66, 16#2d, + 16#75, 16#6e, 16#6d, 16#6f, 16#64, 16#69, 16#66, 16#69, + 16#65, 16#64, 16#2d, 16#73, 16#69, 16#6e, 16#63, 16#65, + 16#00, 16#00, 16#00, 16#0d, 16#6c, 16#61, 16#73, 16#74, + 16#2d, 16#6d, 16#6f, 16#64, 16#69, 16#66, 16#69, 16#65, + 16#64, 16#00, 16#00, 16#00, 16#08, 16#6c, 16#6f, 16#63, + 16#61, 16#74, 16#69, 16#6f, 16#6e, 16#00, 16#00, 16#00, + 16#0c, 16#6d, 16#61, 16#78, 16#2d, 16#66, 16#6f, 16#72, + 16#77, 16#61, 16#72, 16#64, 16#73, 16#00, 16#00, 16#00, + 16#06, 16#70, 16#72, 16#61, 16#67, 16#6d, 16#61, 16#00, + 16#00, 16#00, 16#12, 16#70, 16#72, 16#6f, 16#78, 16#79, + 16#2d, 16#61, 16#75, 16#74, 16#68, 16#65, 16#6e, 16#74, + 16#69, 16#63, 16#61, 16#74, 16#65, 16#00, 16#00, 16#00, + 16#13, 16#70, 16#72, 16#6f, 16#78, 16#79, 16#2d, 16#61, + 16#75, 16#74, 16#68, 16#6f, 16#72, 16#69, 16#7a, 16#61, + 16#74, 16#69, 16#6f, 16#6e, 16#00, 16#00, 16#00, 16#05, + 16#72, 16#61, 16#6e, 16#67, 16#65, 16#00, 16#00, 16#00, + 16#07, 16#72, 16#65, 16#66, 16#65, 16#72, 16#65, 16#72, + 16#00, 16#00, 16#00, 16#0b, 16#72, 16#65, 16#74, 16#72, + 16#79, 16#2d, 16#61, 16#66, 16#74, 16#65, 16#72, 16#00, + 16#00, 16#00, 16#06, 16#73, 16#65, 16#72, 16#76, 16#65, + 16#72, 16#00, 16#00, 16#00, 16#02, 16#74, 16#65, 16#00, + 16#00, 16#00, 16#07, 16#74, 16#72, 16#61, 16#69, 16#6c, + 16#65, 16#72, 16#00, 16#00, 16#00, 16#11, 16#74, 16#72, + 16#61, 16#6e, 16#73, 16#66, 16#65, 16#72, 16#2d, 16#65, + 16#6e, 16#63, 16#6f, 16#64, 16#69, 16#6e, 16#67, 16#00, + 16#00, 16#00, 16#07, 16#75, 16#70, 16#67, 16#72, 16#61, + 16#64, 16#65, 16#00, 16#00, 16#00, 16#0a, 16#75, 16#73, + 16#65, 16#72, 16#2d, 16#61, 16#67, 16#65, 16#6e, 16#74, + 16#00, 16#00, 16#00, 16#04, 16#76, 16#61, 16#72, 16#79, + 16#00, 16#00, 16#00, 16#03, 16#76, 16#69, 16#61, 16#00, + 16#00, 16#00, 16#07, 16#77, 16#61, 16#72, 16#6e, 16#69, + 16#6e, 16#67, 16#00, 16#00, 16#00, 16#10, 16#77, 16#77, + 16#77, 16#2d, 16#61, 16#75, 16#74, 16#68, 16#65, 16#6e, + 16#74, 16#69, 16#63, 16#61, 16#74, 16#65, 16#00, 16#00, + 16#00, 16#06, 16#6d, 16#65, 16#74, 16#68, 16#6f, 16#64, + 16#00, 16#00, 16#00, 16#03, 16#67, 16#65, 16#74, 16#00, + 16#00, 16#00, 16#06, 16#73, 16#74, 16#61, 16#74, 16#75, + 16#73, 16#00, 16#00, 16#00, 16#06, 16#32, 16#30, 16#30, + 16#20, 16#4f, 16#4b, 16#00, 16#00, 16#00, 16#07, 16#76, + 16#65, 16#72, 16#73, 16#69, 16#6f, 16#6e, 16#00, 16#00, + 16#00, 16#08, 16#48, 16#54, 16#54, 16#50, 16#2f, 16#31, + 16#2e, 16#31, 16#00, 16#00, 16#00, 16#03, 16#75, 16#72, + 16#6c, 16#00, 16#00, 16#00, 16#06, 16#70, 16#75, 16#62, + 16#6c, 16#69, 16#63, 16#00, 16#00, 16#00, 16#0a, 16#73, + 16#65, 16#74, 16#2d, 16#63, 16#6f, 16#6f, 16#6b, 16#69, + 16#65, 16#00, 16#00, 16#00, 16#0a, 16#6b, 16#65, 16#65, + 16#70, 16#2d, 16#61, 16#6c, 16#69, 16#76, 16#65, 16#00, + 16#00, 16#00, 16#06, 16#6f, 16#72, 16#69, 16#67, 16#69, + 16#6e, 16#31, 16#30, 16#30, 16#31, 16#30, 16#31, 16#32, + 16#30, 16#31, 16#32, 16#30, 16#32, 16#32, 16#30, 16#35, + 16#32, 16#30, 16#36, 16#33, 16#30, 16#30, 16#33, 16#30, + 16#32, 16#33, 16#30, 16#33, 16#33, 16#30, 16#34, 16#33, + 16#30, 16#35, 16#33, 16#30, 16#36, 16#33, 16#30, 16#37, + 16#34, 16#30, 16#32, 16#34, 16#30, 16#35, 16#34, 16#30, + 16#36, 16#34, 16#30, 16#37, 16#34, 16#30, 16#38, 16#34, + 16#30, 16#39, 16#34, 16#31, 16#30, 16#34, 16#31, 16#31, + 16#34, 16#31, 16#32, 16#34, 16#31, 16#33, 16#34, 16#31, + 16#34, 16#34, 16#31, 16#35, 16#34, 16#31, 16#36, 16#34, + 16#31, 16#37, 16#35, 16#30, 16#32, 16#35, 16#30, 16#34, + 16#35, 16#30, 16#35, 16#32, 16#30, 16#33, 16#20, 16#4e, + 16#6f, 16#6e, 16#2d, 16#41, 16#75, 16#74, 16#68, 16#6f, + 16#72, 16#69, 16#74, 16#61, 16#74, 16#69, 16#76, 16#65, + 16#20, 16#49, 16#6e, 16#66, 16#6f, 16#72, 16#6d, 16#61, + 16#74, 16#69, 16#6f, 16#6e, 16#32, 16#30, 16#34, 16#20, + 16#4e, 16#6f, 16#20, 16#43, 16#6f, 16#6e, 16#74, 16#65, + 16#6e, 16#74, 16#33, 16#30, 16#31, 16#20, 16#4d, 16#6f, + 16#76, 16#65, 16#64, 16#20, 16#50, 16#65, 16#72, 16#6d, + 16#61, 16#6e, 16#65, 16#6e, 16#74, 16#6c, 16#79, 16#34, + 16#30, 16#30, 16#20, 16#42, 16#61, 16#64, 16#20, 16#52, + 16#65, 16#71, 16#75, 16#65, 16#73, 16#74, 16#34, 16#30, + 16#31, 16#20, 16#55, 16#6e, 16#61, 16#75, 16#74, 16#68, + 16#6f, 16#72, 16#69, 16#7a, 16#65, 16#64, 16#34, 16#30, + 16#33, 16#20, 16#46, 16#6f, 16#72, 16#62, 16#69, 16#64, + 16#64, 16#65, 16#6e, 16#34, 16#30, 16#34, 16#20, 16#4e, + 16#6f, 16#74, 16#20, 16#46, 16#6f, 16#75, 16#6e, 16#64, + 16#35, 16#30, 16#30, 16#20, 16#49, 16#6e, 16#74, 16#65, + 16#72, 16#6e, 16#61, 16#6c, 16#20, 16#53, 16#65, 16#72, + 16#76, 16#65, 16#72, 16#20, 16#45, 16#72, 16#72, 16#6f, + 16#72, 16#35, 16#30, 16#31, 16#20, 16#4e, 16#6f, 16#74, + 16#20, 16#49, 16#6d, 16#70, 16#6c, 16#65, 16#6d, 16#65, + 16#6e, 16#74, 16#65, 16#64, 16#35, 16#30, 16#33, 16#20, + 16#53, 16#65, 16#72, 16#76, 16#69, 16#63, 16#65, 16#20, + 16#55, 16#6e, 16#61, 16#76, 16#61, 16#69, 16#6c, 16#61, + 16#62, 16#6c, 16#65, 16#4a, 16#61, 16#6e, 16#20, 16#46, + 16#65, 16#62, 16#20, 16#4d, 16#61, 16#72, 16#20, 16#41, + 16#70, 16#72, 16#20, 16#4d, 16#61, 16#79, 16#20, 16#4a, + 16#75, 16#6e, 16#20, 16#4a, 16#75, 16#6c, 16#20, 16#41, + 16#75, 16#67, 16#20, 16#53, 16#65, 16#70, 16#74, 16#20, + 16#4f, 16#63, 16#74, 16#20, 16#4e, 16#6f, 16#76, 16#20, + 16#44, 16#65, 16#63, 16#20, 16#30, 16#30, 16#3a, 16#30, + 16#30, 16#3a, 16#30, 16#30, 16#20, 16#4d, 16#6f, 16#6e, + 16#2c, 16#20, 16#54, 16#75, 16#65, 16#2c, 16#20, 16#57, + 16#65, 16#64, 16#2c, 16#20, 16#54, 16#68, 16#75, 16#2c, + 16#20, 16#46, 16#72, 16#69, 16#2c, 16#20, 16#53, 16#61, + 16#74, 16#2c, 16#20, 16#53, 16#75, 16#6e, 16#2c, 16#20, + 16#47, 16#4d, 16#54, 16#63, 16#68, 16#75, 16#6e, 16#6b, + 16#65, 16#64, 16#2c, 16#74, 16#65, 16#78, 16#74, 16#2f, + 16#68, 16#74, 16#6d, 16#6c, 16#2c, 16#69, 16#6d, 16#61, + 16#67, 16#65, 16#2f, 16#70, 16#6e, 16#67, 16#2c, 16#69, + 16#6d, 16#61, 16#67, 16#65, 16#2f, 16#6a, 16#70, 16#67, + 16#2c, 16#69, 16#6d, 16#61, 16#67, 16#65, 16#2f, 16#67, + 16#69, 16#66, 16#2c, 16#61, 16#70, 16#70, 16#6c, 16#69, + 16#63, 16#61, 16#74, 16#69, 16#6f, 16#6e, 16#2f, 16#78, + 16#6d, 16#6c, 16#2c, 16#61, 16#70, 16#70, 16#6c, 16#69, + 16#63, 16#61, 16#74, 16#69, 16#6f, 16#6e, 16#2f, 16#78, + 16#68, 16#74, 16#6d, 16#6c, 16#2b, 16#78, 16#6d, 16#6c, + 16#2c, 16#74, 16#65, 16#78, 16#74, 16#2f, 16#70, 16#6c, + 16#61, 16#69, 16#6e, 16#2c, 16#74, 16#65, 16#78, 16#74, + 16#2f, 16#6a, 16#61, 16#76, 16#61, 16#73, 16#63, 16#72, + 16#69, 16#70, 16#74, 16#2c, 16#70, 16#75, 16#62, 16#6c, + 16#69, 16#63, 16#70, 16#72, 16#69, 16#76, 16#61, 16#74, + 16#65, 16#6d, 16#61, 16#78, 16#2d, 16#61, 16#67, 16#65, + 16#3d, 16#67, 16#7a, 16#69, 16#70, 16#2c, 16#64, 16#65, + 16#66, 16#6c, 16#61, 16#74, 16#65, 16#2c, 16#73, 16#64, + 16#63, 16#68, 16#63, 16#68, 16#61, 16#72, 16#73, 16#65, + 16#74, 16#3d, 16#75, 16#74, 16#66, 16#2d, 16#38, 16#63, + 16#68, 16#61, 16#72, 16#73, 16#65, 16#74, 16#3d, 16#69, + 16#73, 16#6f, 16#2d, 16#38, 16#38, 16#35, 16#39, 16#2d, + 16#31, 16#2c, 16#75, 16#74, 16#66, 16#2d, 16#2c, 16#2a, + 16#2c, 16#65, 16#6e, 16#71, 16#3d, 16#30, 16#2e >>). diff --git a/src/cowlib.app.src b/src/cowlib.app.src new file mode 100644 index 0000000..c5d0d62 --- /dev/null +++ b/src/cowlib.app.src @@ -0,0 +1,24 @@ +%% Copyright (c) 2013, Loïc Hoguin +%% +%% Permission to use, copy, modify, and/or distribute this software for any +%% purpose with or without fee is hereby granted, provided that the above +%% copyright notice and this permission notice appear in all copies. +%% +%% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +%% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +%% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +%% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +%% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +%% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +%% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +{application, cowlib, [ + {description, "Support library for manipulating Web protocols."}, + {vsn, "0.1.0"}, + {modules, []}, + {registered, []}, + {applications, [ + kernel, + stdlib + ]} +]}. -- cgit v1.2.3