]>
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 char* cgirls_gobblepath(char const* ndx
[1], char const*const end
[1]) {
24 char const* eor
= strchr(ndx
[0], '/');
25 char* result
= nullptr;
30 result
= strndup(ndx
[0], eor
- ndx
[0]);
40 cgirls_req
cgirls_path2req(char const*const pathinfo
) {
41 assert(pathinfo
!= nullptr);
43 // Initialize the result.
45 .cgirls_action
= cgirls_vb_unknown
,
46 .cgirls_type
= cgirls_mtype_any
,
47 .cgirls_project
= nullptr,
49 .cgirls_subpath
= nullptr,
50 .cgirls_baseid
= nullptr,
53 .cgirls_message
= nullptr,
57 // `ndx´ stores the start of the next term; `end´ stores the end of
58 // the `pathinfo´ string.
59 char const* ndx
[1] = { pathinfo
};
60 char const*const end
[1] = { strchr(pathinfo
, 0) };
61 assert(end
[0] != nullptr);
63 // The portion of the pathinfo which precedes the first slash gives
64 // the project of the request. If there is no first slash, the
65 // project extends to the end of the string. An empty string is
66 // equivalent to having no project.
67 req
.cgirls_project
= cgirls_gobblepath(ndx
, end
);
69 // The portion of the pathinfo which follows the first slash but
70 // precedes the second gives the action of the request. If there is
71 // no second slash, the action extends to the end of the string. If
72 // the action is not present, or is the empty string, it is treated
73 // as `"index"´, unless the second slash is present, in which case it
74 // is treated as `"unknown"´.
76 // Actions consist of verbs optionally suffixed with one of a small
77 // number of extensions to request a specific type of response.
79 // Only a few verbs are recognized (corresponding to the `cgirls_vb´
80 // constants). If a verb is present, but unrecognized, it is assigned
81 // the special value `cgirls_vb_unknown´, which should generally be
82 // interpreted as an error.
83 char* soa
= cgirls_gobblepath(ndx
, end
);
85 char*const eoa
= strchr(soa
, 0);
87 // If the verb is at least 5 characters, extract the extension if
88 // present (it will be the last 4). Then set the first character
89 // of the extension to null, effectively trimming the verb.
91 for (size_t i
= 0; i
< cgirls_n·mtypes
; ++i
) {
92 cgirls_mtype ixt
= cgirls_mtypes
[i
];
93 if (strncmp(ext
, ixt
, 4) == 0) {
94 req
.cgirls_type
= ixt
;
100 for (size_t i
= 0; i
< cgirls_n·parsable·vbs
; ++i
) {
101 cgirls_vb ivb
= cgirls_parsable·vbs
[i
];
102 if (strcmp(soa
, ivb
) == 0) {
103 req
.cgirls_action
= ivb
;
108 } else if (ndx
[0] == end
[0]) {
109 req
.cgirls_action
= cgirls_vb_index
;
112 // The portion of the pathinfo which follows the second slash but
113 // precedes the third identifies the identifiers for the request. If
114 // there is no third slash, the identifiers extend to the end of the
115 // string. A single identifier may be given, or two identifiers may
116 // be given separated by two periods. An empty string is equivalent
118 char* idid
= cgirls_gobblepath(ndx
, end
);
120 // If the identifier string contains two successive dots, the base
121 // and target identifiers must be extracted and the original
122 // identifier string freed. Otherwise, the identifier string is the
123 // target identifier, and there is no base.
124 char const*const dots
= strstr(idid
, "..");
126 char const*const eods
= dots
+ 2;
127 char const*const eoii
= strchr(idid
, 0);
129 req
.cgirls_baseid
= strndup(idid
, dots
- idid
);
132 req
.cgirls_id
= strndup(eods
, eoii
- eods
);
136 req
.cgirls_id
= idid
;
140 // The portion of the pathinfo which follows the third slash is the
141 // subpath of the request. An empty sting is equivalent to having no
142 // subpath. Trailing and successive slashes are dropped.
143 char const* sos
= ndx
[0];
144 char const* sep
= nullptr;
146 while (end
[0] > sos
) {
147 // Count the number of segments in the pathinfo so that the correct
148 // amount of space can be allocated.
149 sep
= strchr(sos
, '/');
162 req
.cgirls_subpath
= calloc(n·s
+ 1, sizeof(char*));
163 if (!req
.cgirls_subpath
) {
167 while (end
[0] > ndx
[0]) {
168 // Add the segments to the newly allocated array.
169 sep
= strchr(ndx
[0], '/');
174 req
.cgirls_subpath
[i·s
++] = strndup(ndx
[0], sep
- ndx
[0]);
183 req
.cgirls_subpath
[i·s
] = nullptr;
185 // Return the result.
189 char* cgirls_req2path(cgirls_req req
) {
190 cgirls_vb vb
= cgirls_vb_index
;
191 bool has·ids
= req
.cgirls_baseid
|| req
.cgirls_id
;
192 bool has·type
= req
.cgirls_type
;
193 bool has·subpath
= req
.cgirls_subpath
&& req
.cgirls_subpath
[0];
196 // Get the length of the various parts. This length includes a
197 // trailing slash, but in practice this will be replaced by the final
199 if (req
.cgirls_project
) {
200 length
+= strlen(req
.cgirls_project
) + 1;
201 for (size_t i
= 0; i
< cgirls_n·vbs
; ++i
) {
202 cgirls_vb ivb
= cgirls_vbs
[i
];
203 if (req
.cgirls_action
== ivb
) {
208 if (vb
!= cgirls_vb_index
|| has·type
|| has·ids
|| has·subpath
) {
209 length
+= strlen(vb
) + 1;
212 length
+= strlen(req
.cgirls_type
);
215 if (req
.cgirls_baseid
) {
216 length
+= strlen(req
.cgirls_baseid
) + 2;
219 length
+= strlen(req
.cgirls_id
);
222 } else if (has·subpath
) {
227 char* c
= req
.cgirls_subpath
[i
];
229 length
+= strlen(c
) + 1;
230 c
= req
.cgirls_subpath
[++i
];
234 // If there is no project, then the action must be removed, and the
235 // length is just that of the trailing slash.
238 // Create and compose the final path.
239 char* result
= calloc(length
, sizeof(char*));
243 char* cursor
= result
;
244 if (req
.cgirls_project
) {
245 cursor
= stpcpy(cursor
, req
.cgirls_project
);
247 if (vb
!= cgirls_vb_index
|| has·type
|| has·ids
|| has·subpath
) {
248 cursor
= stpcpy(cursor
, vb
);
250 cursor
= stpcpy(cursor
, req
.cgirls_type
);
255 if (req
.cgirls_baseid
) {
256 cursor
= stpcpy(cursor
, req
.cgirls_baseid
);
257 cursor
= stpcpy(cursor
, "..");
260 cursor
= stpcpy(cursor
, req
.cgirls_id
);
263 } else if (has·subpath
) {
264 cursor
= stpcpy(cursor
, "../");
268 char* c
= req
.cgirls_subpath
[i
];
270 cursor
= stpcpy(cursor
, c
);
271 c
= req
.cgirls_subpath
[++i
];
279 // At this point, `cursor´ points one ⹐past⹑ the last element of the
280 // array (this is allowed in C), and the last element is a slash.
281 // Rewind and set it to the null byte, and assert that everything was
284 assert((cursor
+ 1) - result
== length
);
This page took 0.371487 seconds and 5 git commands to generate.