form.d 3.7 KB

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