]>
Lady’s Gitweb - CGirls/blob - request.c
1 // SPDX-FileCopyrightText: 2025 Lady <https://www.ladys.computer/about/#lady>
2 // SPDX-License-Identifier: GPL-2.0-only
7 void cgirls_freereq (cgirls_req req
) {
8 free(req
.cgirls_project
);
10 if (req
.cgirls_subpath
) {
12 char* c
= req
.cgirls_subpath
[i
];
15 c
= req
.cgirls_subpath
[++i
];
17 free(req
.cgirls_subpath
);
19 free(req
.cgirls_baseid
);
20 free(req
.cgirls_status
.cgirls_message
);
23 cgirls_req
cgirls_path2req(char const*const pathinfo
) {
24 assert(pathinfo
!= nullptr);
26 // Initialize the result.
28 .cgirls_action
= cgirls_vb_index
,
29 .cgirls_type
= cgirls_mediatype_any
,
30 .cgirls_project
= nullptr,
32 .cgirls_subpath
= nullptr,
33 .cgirls_baseid
= nullptr,
36 .cgirls_message
= nullptr,
40 // `sont´ stores the start of the next term; `eopi´ stores the end of
41 // the `pathinfo´ string, excluding any extension.
42 char const* sont
= pathinfo
;
43 char const*const eopi
= strchr(pathinfo
, 0);
45 // The portion of the pathinfo which precedes the first slash gives
46 // the project of the request. If there is no first slash, the
47 // project extends to the end of the string. An empty string is
48 // equivalent to having no project.
49 char const* eopj
= strchr(sont
, '/');
54 req
.cgirls_project
= strndup(sont
, eopj
- sont
);
62 // The portion of the pathinfo which follows the first slash but
63 // precedes the second gives the verb of the request. If there is no
64 // second slash, the verb extends to the end of the string. If the
65 // verb is not present, or is the empty string, it is treated as
66 // `"index"´, unless the second slash is present, in which case it is
67 // treated as `"unknown"´.
69 // Verbs may be suffixed with one of a small number of extensions to
70 // request a specific type of response.
72 // Only a few verbs are recognized (corresponding to the `cgirls_vb´
73 // constants). If a verb is present, but unrecognized, it is assigned
74 // the special value `cgirls_vb_unknown´, which should generally be
75 // interpreted as an error.
76 char const* eovb
= strchr(sont
, '/');
80 char const*const eove
= eovb
;
82 if (eovb
- sont
> 4) {
83 // If the verb is at least 5 characters, extract the extension if
84 // present (it will be the last 4), and then set the end of the
85 // verb to the start of the extension.
86 char const* exts
= eovb
- 4;
88 // This “loop” encapsulates extension checking for readability.
89 // If an extension matches, `eovb´ is re·assigned to point to the
90 // beginning of the extension. Otherwise, the loop exits early
91 // and `eovb´ keeps pointing at the end of the string.
92 if (strncmp(exts
, ".txt", 4) == 0) {
93 req
.cgirls_type
= cgirls_mediatype_txt
;
94 } else if (strncmp(exts
, ".htm", 4) == 0) {
95 req
.cgirls_type
= cgirls_mediatype_htm
;
96 } else if (strncmp(exts
, ".xml", 4) == 0) {
97 req
.cgirls_type
= cgirls_mediatype_xml
;
98 } else if (strncmp(exts
, ".rdf", 4) == 0) {
99 req
.cgirls_type
= cgirls_mediatype_rdf
;
101 break; // do not re·assign `eovb´
107 verb
= strndup(sont
, eovb
- sont
);
115 if (strcmp(verb
, "branches") == 0) {
116 req
.cgirls_action
= cgirls_vb_branches
;
117 } else if (strcmp(verb
, "tags") == 0) {
118 req
.cgirls_action
= cgirls_vb_tags
;
119 } else if (strcmp(verb
, "show") == 0) {
120 req
.cgirls_action
= cgirls_vb_show
;
121 } else if (strcmp(verb
, "raw") == 0) {
122 req
.cgirls_action
= cgirls_vb_raw
;
123 } else if (strcmp(verb
, "blame") == 0) {
124 req
.cgirls_action
= cgirls_vb_blame
;
125 } else if (strcmp(verb
, "log") == 0) {
126 req
.cgirls_action
= cgirls_vb_log
;
127 } else if (strcmp(verb
, "shortlog") == 0) {
128 req
.cgirls_action
= cgirls_vb_shortlog
;
129 } else if (strcmp(verb
, "atom") == 0) {
130 req
.cgirls_action
= cgirls_vb_atom
;
131 } else if (strcmp(verb
, "patch") == 0) {
132 req
.cgirls_action
= cgirls_vb_patch
;
133 } else if (strcmp(verb
, "index") != 0) {
134 req
.cgirls_action
= cgirls_vb_unknown
;
137 } else if (eovb
< eopi
) {
138 req
.cgirls_action
= cgirls_vb_unknown
;
141 // The portion of the pathinfo which follows the second slash but
142 // precedes the third identifies the identifiers for the request. If
143 // there is no third slash, the identifiers extend to the end of the
144 // string. A single identifier may be given, or two identifiers may
145 // be given separated by two periods. An empty string is equivalent
147 char const* eoid
= strchr(sont
, '/');
151 char* idid
= nullptr;
153 idid
= strndup(sont
, eoid
- sont
);
161 // If the identifier string contains two successive dots, the base
162 // and target identifiers must be extracted and the original
163 // identifier string freed. Otherwise, the identifier string is the
164 // target identifier, and there is no base.
165 char const*const dots
= strstr(idid
, "..");
167 char const*const eods
= dots
+ 2;
168 char const*const eoii
= strchr(idid
, 0);
170 req
.cgirls_baseid
= strndup(idid
, dots
- idid
);
173 req
.cgirls_id
= strndup(eods
, eoii
- eods
);
177 req
.cgirls_id
= idid
;
181 // The portion of the pathinfo which follows the third slash is the
182 // subpath of the request. An empty sting is equivalent to having no
183 // subpath. Trailing and successive slashes are dropped.
184 char const* soct
= sont
;
185 char const* psep
= nullptr;
187 while (eopi
> soct
) {
188 // Count the number of segments in the pathinfo so that the correct
189 // amount of space can be allocated.
190 psep
= strchr(soct
, '/');
203 req
.cgirls_subpath
= calloc(npth
+ 1, sizeof(char*));
204 if (!req
.cgirls_subpath
) {
208 while (eopi
> sont
) {
209 // Add the segments to the newly allocated array.
210 psep
= strchr(sont
, '/');
215 req
.cgirls_subpath
[pthi
++] = strndup(sont
, psep
- sont
);
223 assert(pthi
== npth
);
224 req
.cgirls_subpath
[pthi
] = nullptr;
226 // Return the result.
230 char* cgirls_req2path(cgirls_req req
) {
231 char* action
= "unknown";
233 size_t length
= 8; // length of `action´ plus 1, to start
235 // Get the length of the various parts, saving the verb and the
236 // extension. This length includes a trailing slash, but in practice
237 // this will be replaced by the final null byte.
238 switch (req
.cgirls_action
) {
239 case cgirls_vb_index
:
243 case cgirls_vb_branches
:
259 case cgirls_vb_blame
:
267 case cgirls_vb_shortlog
:
275 case cgirls_vb_patch
:
282 switch (req
.cgirls_type
) {
283 case cgirls_mediatype_txt
:
286 case cgirls_mediatype_htm
:
289 case cgirls_mediatype_xml
:
292 case cgirls_mediatype_rdf
:
298 if (req
.cgirls_project
) {
299 length
+= strlen(req
.cgirls_project
) + 1;
300 if (req
.cgirls_type
!= cgirls_mediatype_any
) {
303 if (req
.cgirls_baseid
|| req
.cgirls_id
) {
304 if (req
.cgirls_baseid
) {
305 length
+= strlen(req
.cgirls_baseid
) + 2;
308 length
+= strlen(req
.cgirls_id
);
311 } else if (req
.cgirls_subpath
&& req
.cgirls_subpath
[0]) {
314 if (req
.cgirls_subpath
) {
316 char* c
= req
.cgirls_subpath
[i
];
318 length
+= strlen(c
) + 1;
319 c
= req
.cgirls_subpath
[++i
];
323 // If there is no project, then the action must be removed, and the
324 // length is just that of the trailing slash.
327 // Create and compose the final path.
328 char* result
= calloc(length
, sizeof(char*));
332 char* cursor
= result
;
333 if (req
.cgirls_project
) {
334 cursor
= stpcpy(cursor
, req
.cgirls_project
);
336 cursor
= stpcpy(cursor
, action
);
337 if (req
.cgirls_type
!= cgirls_mediatype_any
) {
338 cursor
= stpcpy(cursor
, extnsn
);
341 if (req
.cgirls_baseid
|| req
.cgirls_id
) {
342 if (req
.cgirls_baseid
) {
343 cursor
= stpcpy(cursor
, req
.cgirls_baseid
);
349 cursor
= stpcpy(cursor
, req
.cgirls_id
);
352 } else if (req
.cgirls_subpath
&& req
.cgirls_subpath
[0]) {
353 cursor
= stpcpy(cursor
, "../");
355 if (req
.cgirls_subpath
) {
357 char* c
= req
.cgirls_subpath
[i
];
359 cursor
= stpcpy(cursor
, c
);
360 c
= req
.cgirls_subpath
[++i
];
368 // At this point, `cursor´ points one ⹐past⹑ the last element of the
369 // array (this is allowed in C), and the last element is a slash.
370 // Rewind and set it to the null byte, and assert that everything was
373 assert((cursor
+ 1) - result
== length
);
This page took 0.377929 seconds and 5 git commands to generate.