ksgi

Форк
0
/
tutorial1.xml 
154 строки · 6.5 Кб
1
<article data-sblg-article="1" data-sblg-tags="tutorial" itemscope="itemscope" itemtype="http://schema.org/BlogPosting">
2
	<header>
3
		<h2 itemprop="name">
4
			Getting and Setting CGI Cookies in C
5
		</h2>
6
		<address itemprop="author"><a href="https://kristaps.bsd.lv">Kristaps Dzonsons</a></address>
7
		<time itemprop="datePublished" datetime="2015-07-07">7 July, 2015</time>
8
	</header>
9
	<p>
10
		<aside itemprop="about">
11
			Cookies are an integral part of any web application.
12
			In this tutorial, I'll describe how to use the HTTP header functionality in <span class="nm">kcgi</span> to set,
13
			recognise, and store cookies.
14
		</aside>
15
	</p>
16
	<h3>
17
		Source Code
18
	</h3>
19
	<p>
20
		Setting and getting cookies with <span class="nm">kcgi</span> is easy.
21
		It uses the same logic as setting and getting form fields.
22
		Cookies consist of name-value pairs that we can grok from a table.
23
		I'll lead this tutorial as if we were reading a source file from top to bottom, so let's start with headers.
24
		We'll obviously need <span class="nm">kcgi</span> and <span class="file">stdint.h</span>, which is necessary for some types
25
		found in the header file.
26
	</p>
27
	<figure class="sample">
28
		<pre class="prettyprint linenums">#include &lt;sys/types.h&gt; /* size_t, ssize_t */
29
#include &lt;stdarg.h&gt; /* va_list */
30
#include &lt;stddef.h&gt; /* NULL */
31
#include &lt;stdint.h&gt; /* int64_t */
32
#include &lt;time.h&gt; /* time(3) */
33
#include &lt;kcgi.h&gt;</pre>
34
	</figure>
35
	<p>
36
		Next, let's define identifiers for our cookies.
37
		These will later be mapped to the cookie names and the validators for their values.
38
	</p>
39
	<figure class="sample">
40
		<pre class="prettyprint linenums">enum cookie {
41
  COOKIE_STRING,
42
  COOKIE_INTEGER,
43
  COOKIE__MAX
44
};</pre>
45
	</figure>
46
	<p>
47
		The enumeration will allow us to bound an array to <code>COOKIE__MAX</code> and refer to individual buckets in the array by the
48
		enumeration value.
49
		I'll assume that <code>COOKIE_STRING</code> is assigned 0 and <code>COOKIE_INTEGER</code>, 1.
50
	</p>
51
	<p>
52
		Next, connect the indices with validation functions and names.
53
		The validation function is run by <a href="khttp_parse.3.html">khttp_parse(3)</a>; the name is the cookie key name.
54
		Built-in validation functions, which we'll use, are described in <a href="kvalid_string.3.html">kvalid_string(3)</a>.
55
		In this example, <code>kvalid_stringne</code> will validate a non-empty (nil-terminated) C string, while <code>kvalid_int</code>
56
		will validate a signed 64-bit integer.
57
	</p>
58
	<figure class="sample">
59
		<pre class="prettyprint linenums">static const struct kvalid cookies[COOKIE__MAX] = {
60
  { kvalid_stringne, "string" }, /* COOKIE_STRING */
61
  { kvalid_int, "integer" }, /* COOKIE_INTEGER */
62
};</pre>
63
	</figure>
64
	<p>
65
		Before doing any parsing, I sanitise the HTTP context.
66
		I'll let any page request pass, but will make sure our MIME type and HTTP method are sane.
67
	</p>
68
	<figure class="sample">
69
		<pre class="prettyprint linenums">static enum khttp sanitise(const struct kreq *r) {
70
  if (r->mime != KMIME_TEXT_HTML)
71
    return KHTTP_404;
72
  else if (r->method != KMETHOD_GET)
73
    return KHTTP_405;
74
  else
75
    return KHTTP_200;
76
}</pre> 
77
	</figure>
78
	<p>
79
		Now the scaffolding is done.
80
		What about the cookies?
81
		To begin with, you should glance at the <a href="https://tools.ietf.org/html/rfc6265">RFC 6265</a>, <q>HTTP State Management
82
			Mechanism</q>, to gain an understanding of how cookies work.
83
		You may also want to read about the <a href="https://www.owasp.org/index.php/HttpOnly">HttpOnly</a>
84
		and
85
		<a href="https://www.owasp.org/index.php/SecureFlag">Secure</a> flags also available.
86
		In our application, let's just attempt to read the cookie; and if it doesn't exist, write the cookie along with the page.
87
		If it does exist, we'll indicate that in our page.
88
		We'll focus only on the <code>COOKIE_STRING</code> cookie, and will set the cookie to be visible to the path root and expire in
89
		an hour.
90
		We'll use <a href="kutil_epoch2str.3.html">kutil_epoch2str(3)</a> to format the date.
91
		Headers are output using <a href="khttp_head.3.html">khttp_head(3)</a>, with the document body started
92
		with <a href="khttp_body.3.html">khttp_body(3)</a>.
93
	</p>
94
	<figure class="sample">
95
		<pre class="prettyprint linenums">static void process(struct kreq *r) {
96
  char buf[32];			 
97
  khttp_head(r, kresps[KRESP_STATUS],
98
    "%s", khttps[KHTTP_200]);
99
  khttp_head(r, kresps[KRESP_CONTENT_TYPE],
100
    "%s", kmimetypes[r->mime]);
101
  if (r->cookiemap[COOKIE_STRING] == NULL)
102
    khttp_head(r, kresps[KRESP_SET_COOKIE],
103
      "%s=%s; Path=/; expires=%s", 
104
      cookies[COOKIE_STRING].name, 
105
      "Hello, world!",
106
      kutil_epoch2str(time(NULL) + 60 * 60, 
107
        buf, sizeof(buf)));
108
  khttp_body(r);
109
  khttp_puts(r, 
110
    "&lt;!DOCTYPE html&gt;"
111
    "&lt;title&gt;Foo&lt;/title&gt;");
112
  if (r->cookiemap[COOKIE_STRING] != NULL)
113
    khttp_puts(r, "Cookie found!");
114
  else
115
    khttp_puts(r, "Cookie set.");
116
}</pre> 
117
	</figure>
118
	<p>
119
		Most of the above code is just to handle the HTML5 bits, and we deliberately used the smallest possible page.
120
		(Yes, this is a valid page&#8212;<a href="https://validator.w3.org/nu/">validate</a> it yourself to find out!)
121
		For any significant page, you'd want to use <a href="kcgihtml.3.html">kcgihtml(3)</a>.
122
	</p>
123
	<p>
124
		Putting all of these together: parse the HTTP context, validate it, process it, then free the resources.
125
		The HTTP context is closed with <a href="khttp_free.3.html">khttp_free(3)</a>.
126
		Note that the identifiers for the cookies, <code>enum cookie</code>, are also used to identify any form input.
127
		So if you have both form input and cookies (which is common), they can either share identifiers or use unique ones.
128
		In other words, <code>COOKIE__MAX</code> defines the size of both <code>fieldmap</code> and <code>cookiemap</code>, so the
129
		validator for <code>COOKIE_STRING</code> is also valid for form inputs of the same name.
130
	</p>
131
	<figure class="sample">
132
		<pre class="prettyprint linenums">int main(void) {
133
  struct kreq r;
134
  enum khttp er;
135
  if (khttp_parse(&amp;r, cookies, COOKIE__MAX, NULL, 0, 0) != KCGI_OK)
136
    return 0;
137
  if ((er = sanitise(&amp;r)) != KHTTP_200) {
138
    khttp_head(&amp;r, kresps[KRESP_STATUS],
139
      "%s", khttps[er]);
140
    khttp_head(&amp;r, kresps[KRESP_CONTENT_TYPE],
141
      "%s", kmimetypes[KMIME_TEXT_PLAIN]);
142
    khttp_body(&amp;r);
143
    if (r.mime == KMIME_TEXT_HTML)
144
      khttp_puts(&amp;r, "Could not service request.");
145
  } else
146
    process(&amp;r);
147
  khttp_free(&amp;r);
148
  return 0;
149
}</pre>
150
	</figure>
151
	<p>
152
		For compilation, linking, and installation, see <a href="tutorial0.html">Getting Started with CGI in C</a>.
153
	</p>
154
</article>
155

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.