1 /**
2 	Convenience functions for working with web forms.
3 
4 	Copyright: © 2012-2015 Sönke Ludwig
5 	License: Subject to the terms of the MIT license, as written in the included LICENSE.txt file.
6 	Authors: Sönke Ludwig, Jan Krüger
7 */
8 deprecated("Use vibe.inet.webform instead")
9 module vibe.http.form;
10 
11 public import vibe.inet.webform;
12 
13 import vibe.http.client : HTTPClientRequest; // for writeFormBody
14 import vibe.http.server;
15 
16 import std.array;
17 import std.conv;
18 import std.range;
19 import std..string;
20 import std.typecons : isTuple;
21 
22 
23 /**
24 	Encodes the given dictionary as URL encoded form data.
25 */
26 void writeFormData(R)(R dst, in string[string] data)
27 	if (isOutputRange!(R, char))
28 {
29 	import vibe.textfilter.urlencode;
30 
31 	bool first = true;
32 	foreach (k, v; data) {
33 		if (first) first = false;
34 		else dst.put("&");
35 		filterURLEncode(dst, k);
36 		dst.put("=");
37 		filterURLEncode(dst, v);
38 	}
39 }
40 
41 ///
42 unittest {
43 	import std.array;
44 	import vibe.core.log;
45 	import vibe.http.form;
46 
47 	void test()
48 	{
49 		auto dst = appender!string();
50 		dst.writeFormData(["field1": "value1", "field2": "value2"]);
51 		logInfo("Form data: %s", dst.data);
52 	}
53 }
54 
55 /**
56 	Encodes the given ranges of `Tuple!(string, string)` as URL encoded form data
57 */
58 void writeFormData(R, PairRange)(R dst, PairRange pr)
59 	if (isOutputRange!(R, char) && isTuple!(ElementType!PairRange) && ElementType!PairRange.length == 2)
60 {
61 	import vibe.textfilter.urlencode;
62 
63    if(pr.empty) return;
64 
65    auto fst = pr.front;
66    pr.popFront();
67 
68    filterURLEncode(dst, fst[0]);
69    dst.put("=");
70    filterURLEncode(dst, fst[1]);
71 
72 	foreach (pair; pr) {
73 		dst.put("&");
74 		filterURLEncode(dst, pair[0]);
75 		dst.put("=");
76 		filterURLEncode(dst, pair[1]);
77 	}
78 }
79 
80 /**
81 	Writes a `vibe.http.client.HTTPClientRequest` body as URL encoded form data.
82 */
83 void writeFormBody(HTTPClientRequest req, in string[string] form)
84 {
85 	import vibe.http.form;
86 	import vibe.stream.wrapper;
87 
88 	StringLengthCountingRange len;
89 	writeFormData(&len, form);
90 	req.contentType = "application/x-www-form-urlencoded";
91 	req.contentLength = len.count;
92 	auto rng = streamOutputRange(req.bodyWriter);
93 	writeFormData(&rng, form);
94 }
95 
96 ///
97 unittest {
98 	import vibe.core.log;
99 	import vibe.http.client;
100 	import vibe.http.form;
101 	import vibe.stream.operations;
102 
103 	void sendForm()
104 	{
105 		requestHTTP("http://example.com/form",
106 			(scope req) {
107 				req.method = HTTPMethod.POST;
108 				req.writeFormBody(["field1": "value1", "field2": "value2"]);
109 			},
110 			(scope res) {
111 				logInfo("Response: %s", res.bodyReader.readAllUTF8());
112 			});
113 	}
114 }
115 
116 /**
117 	Writes a `vibe.http.client.HTTPClientRequest` body as URL encoded form data.
118 
119 	Params:
120 	  req  = Request object to write to.
121 	  form = range of `t = Tuple!(string, string)`,
122 			 where `t[0]` is the name and `t[1]` the
123 			 value of a form entry.
124 */
125 void writeFormBody(PairRange)(HTTPClientRequest req, PairRange form)
126    if(isTuple!(ElementType!PairRange) && ElementType!PairRange.length == 2)
127 {
128 	import vibe.http.form;
129 	import vibe.stream.wrapper;
130 
131 	StringLengthCountingRange len;
132 	writeFormData(&len, form.save);
133 	req.contentType = "application/x-www-form-urlencoded";
134 	req.contentLength = len.count;
135 	auto rng = streamOutputRange(req.bodyWriter);
136 	writeFormData(&rng, form);
137 }
138 
139 ///
140 unittest {
141 	import vibe.core.log;
142 	import vibe.http.client;
143 	import vibe.http.form;
144 	import vibe.stream.operations;
145 	import std.range;
146 
147 	void sendForm()
148 	{
149 		string[] names = ["foo", "bar", "baz"];
150 		string[] values = ["1", "2", "3"];
151 		auto form = zip(names, values);
152 		requestHTTP("http://example.com/form",
153 			(scope req) {
154 				req.method = HTTPMethod.POST;
155 				req.writeFormBody(form);
156 			},
157 			(scope res) {
158 				logInfo("Response: %s", res.bodyReader.readAllUTF8());
159 			});
160 	}
161 }
162 
163 
164 /// private
165 struct StringLengthCountingRange {
166 	import std.utf;
167 	size_t count = 0;
168 	void put(string str) { count += str.length; }
169 	void put(dchar ch) { count += codeLength!char(ch); }
170 }