summaryrefslogtreecommitdiffabout
authorLars Hjemli <hjemli@gmail.com>2008-05-18 21:59:11 (UTC)
committer Lars Hjemli <hjemli@gmail.com>2008-05-18 21:59:11 (UTC)
commitaf2e75616d1bfb7dc79d299d10ae0bd39bef47bc (patch) (unidiff)
tree6330a6f9bc1b2b16434df055ee48129e2e3b827e
parentcdc6b2f8e7a8d43dcfe0475a9d3498333ea686b8 (diff)
downloadcgit-af2e75616d1bfb7dc79d299d10ae0bd39bef47bc.zip
cgit-af2e75616d1bfb7dc79d299d10ae0bd39bef47bc.tar.gz
cgit-af2e75616d1bfb7dc79d299d10ae0bd39bef47bc.tar.bz2
cache.c: do not ignore errors from print_slot()
If print_slot() fails, the client will be served an inferior response. This patch makes sure that such an error will be returned to main(), which in turn will try to inform about the error in the response itself. The error is also printed to the cache_log, i.e. stderr, which will make the error message appear in error_log (atleast when httpd==apache). Noticed-by: Jim Meyering <jim@meyering.net> Signed-off-by: Lars Hjemli <hjemli@gmail.com>
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--cache.c16
-rw-r--r--cgit.c4
2 files changed, 15 insertions, 5 deletions
diff --git a/cache.c b/cache.c
index a996109..aa97ae1 100644
--- a/cache.c
+++ b/cache.c
@@ -223,102 +223,112 @@ static int process_slot(struct cache_slot *slot)
223 int err; 223 int err;
224 224
225 err = open_slot(slot); 225 err = open_slot(slot);
226 if (!err && slot->match) { 226 if (!err && slot->match) {
227 if (is_expired(slot)) { 227 if (is_expired(slot)) {
228 if (!lock_slot(slot)) { 228 if (!lock_slot(slot)) {
229 /* If the cachefile has been replaced between 229 /* If the cachefile has been replaced between
230 * `open_slot` and `lock_slot`, we'll just 230 * `open_slot` and `lock_slot`, we'll just
231 * serve the stale content from the original 231 * serve the stale content from the original
232 * cachefile. This way we avoid pruning the 232 * cachefile. This way we avoid pruning the
233 * newly generated slot. The same code-path 233 * newly generated slot. The same code-path
234 * is chosen if fill_slot() fails for some 234 * is chosen if fill_slot() fails for some
235 * reason. 235 * reason.
236 * 236 *
237 * TODO? check if the new slot contains the 237 * TODO? check if the new slot contains the
238 * same key as the old one, since we would 238 * same key as the old one, since we would
239 * prefer to serve the newest content. 239 * prefer to serve the newest content.
240 * This will require us to open yet another 240 * This will require us to open yet another
241 * file-descriptor and read and compare the 241 * file-descriptor and read and compare the
242 * key from the new file, so for now we're 242 * key from the new file, so for now we're
243 * lazy and just ignore the new file. 243 * lazy and just ignore the new file.
244 */ 244 */
245 if (is_modified(slot) || fill_slot(slot)) { 245 if (is_modified(slot) || fill_slot(slot)) {
246 unlock_slot(slot, 0); 246 unlock_slot(slot, 0);
247 close_lock(slot); 247 close_lock(slot);
248 } else { 248 } else {
249 close_slot(slot); 249 close_slot(slot);
250 unlock_slot(slot, 1); 250 unlock_slot(slot, 1);
251 slot->cache_fd = slot->lock_fd; 251 slot->cache_fd = slot->lock_fd;
252 } 252 }
253 } 253 }
254 } 254 }
255 print_slot(slot); 255 if ((err = print_slot(slot)) != 0) {
256 cache_log("[cgit] error printing cache %s: %s (%d)\n",
257 slot->cache_name,
258 strerror(err),
259 err);
260 }
256 close_slot(slot); 261 close_slot(slot);
257 return 0; 262 return err;
258 } 263 }
259 264
260 /* If the cache slot does not exist (or its key doesn't match the 265 /* If the cache slot does not exist (or its key doesn't match the
261 * current key), lets try to create a new cache slot for this 266 * current key), lets try to create a new cache slot for this
262 * request. If this fails (for whatever reason), lets just generate 267 * request. If this fails (for whatever reason), lets just generate
263 * the content without caching it and fool the caller to belive 268 * the content without caching it and fool the caller to belive
264 * everything worked out (but print a warning on stdout). 269 * everything worked out (but print a warning on stdout).
265 */ 270 */
266 271
267 close_slot(slot); 272 close_slot(slot);
268 if ((err = lock_slot(slot)) != 0) { 273 if ((err = lock_slot(slot)) != 0) {
269 cache_log("[cgit] Unable to lock slot %s: %s (%d)\n", 274 cache_log("[cgit] Unable to lock slot %s: %s (%d)\n",
270 slot->lock_name, strerror(err), err); 275 slot->lock_name, strerror(err), err);
271 slot->fn(slot->cbdata); 276 slot->fn(slot->cbdata);
272 return 0; 277 return 0;
273 } 278 }
274 279
275 if ((err = fill_slot(slot)) != 0) { 280 if ((err = fill_slot(slot)) != 0) {
276 cache_log("[cgit] Unable to fill slot %s: %s (%d)\n", 281 cache_log("[cgit] Unable to fill slot %s: %s (%d)\n",
277 slot->lock_name, strerror(err), err); 282 slot->lock_name, strerror(err), err);
278 unlock_slot(slot, 0); 283 unlock_slot(slot, 0);
279 close_lock(slot); 284 close_lock(slot);
280 slot->fn(slot->cbdata); 285 slot->fn(slot->cbdata);
281 return 0; 286 return 0;
282 } 287 }
283 // We've got a valid cache slot in the lock file, which 288 // We've got a valid cache slot in the lock file, which
284 // is about to replace the old cache slot. But if we 289 // is about to replace the old cache slot. But if we
285 // release the lockfile and then try to open the new cache 290 // release the lockfile and then try to open the new cache
286 // slot, we might get a race condition with a concurrent 291 // slot, we might get a race condition with a concurrent
287 // writer for the same cache slot (with a different key). 292 // writer for the same cache slot (with a different key).
288 // Lets avoid such a race by just printing the content of 293 // Lets avoid such a race by just printing the content of
289 // the lock file. 294 // the lock file.
290 slot->cache_fd = slot->lock_fd; 295 slot->cache_fd = slot->lock_fd;
291 unlock_slot(slot, 1); 296 unlock_slot(slot, 1);
292 err = print_slot(slot); 297 if ((err = print_slot(slot)) != 0) {
298 cache_log("[cgit] error printing cache %s: %s (%d)\n",
299 slot->cache_name,
300 strerror(err),
301 err);
302 }
293 close_slot(slot); 303 close_slot(slot);
294 return err; 304 return err;
295} 305}
296 306
297/* Print cached content to stdout, generate the content if necessary. */ 307/* Print cached content to stdout, generate the content if necessary. */
298int cache_process(int size, const char *path, const char *key, int ttl, 308int cache_process(int size, const char *path, const char *key, int ttl,
299 cache_fill_fn fn, void *cbdata) 309 cache_fill_fn fn, void *cbdata)
300{ 310{
301 unsigned long hash; 311 unsigned long hash;
302 int len, i; 312 int len, i;
303 char filename[1024]; 313 char filename[1024];
304 char lockname[1024 + 5]; /* 5 = ".lock" */ 314 char lockname[1024 + 5]; /* 5 = ".lock" */
305 struct cache_slot slot; 315 struct cache_slot slot;
306 316
307 /* If the cache is disabled, just generate the content */ 317 /* If the cache is disabled, just generate the content */
308 if (size <= 0) { 318 if (size <= 0) {
309 fn(cbdata); 319 fn(cbdata);
310 return 0; 320 return 0;
311 } 321 }
312 322
313 /* Verify input, calculate filenames */ 323 /* Verify input, calculate filenames */
314 if (!path) { 324 if (!path) {
315 cache_log("[cgit] Cache path not specified, caching is disabled\n"); 325 cache_log("[cgit] Cache path not specified, caching is disabled\n");
316 fn(cbdata); 326 fn(cbdata);
317 return 0; 327 return 0;
318 } 328 }
319 len = strlen(path); 329 len = strlen(path);
320 if (len > sizeof(filename) - 10) { /* 10 = "/01234567\0" */ 330 if (len > sizeof(filename) - 10) { /* 10 = "/01234567\0" */
321 cache_log("[cgit] Cache path too long, caching is disabled: %s\n", 331 cache_log("[cgit] Cache path too long, caching is disabled: %s\n",
322 path); 332 path);
323 fn(cbdata); 333 fn(cbdata);
324 return 0; 334 return 0;
diff --git a/cgit.c b/cgit.c
index 2036ceb..ac882c3 100644
--- a/cgit.c
+++ b/cgit.c
@@ -351,36 +351,36 @@ static int calc_ttl()
351 return ctx.cfg.cache_static_ttl; 351 return ctx.cfg.cache_static_ttl;
352 352
353 return ctx.cfg.cache_repo_ttl; 353 return ctx.cfg.cache_repo_ttl;
354} 354}
355 355
356int main(int argc, const char **argv) 356int main(int argc, const char **argv)
357{ 357{
358 const char *cgit_config_env = getenv("CGIT_CONFIG"); 358 const char *cgit_config_env = getenv("CGIT_CONFIG");
359 int err, ttl; 359 int err, ttl;
360 360
361 prepare_context(&ctx); 361 prepare_context(&ctx);
362 cgit_repolist.length = 0; 362 cgit_repolist.length = 0;
363 cgit_repolist.count = 0; 363 cgit_repolist.count = 0;
364 cgit_repolist.repos = NULL; 364 cgit_repolist.repos = NULL;
365 365
366 parse_configfile(cgit_config_env ? cgit_config_env : CGIT_CONFIG, 366 parse_configfile(cgit_config_env ? cgit_config_env : CGIT_CONFIG,
367 config_cb); 367 config_cb);
368 ctx.repo = NULL; 368 ctx.repo = NULL;
369 if (getenv("SCRIPT_NAME")) 369 if (getenv("SCRIPT_NAME"))
370 ctx.cfg.script_name = xstrdup(getenv("SCRIPT_NAME")); 370 ctx.cfg.script_name = xstrdup(getenv("SCRIPT_NAME"));
371 if (getenv("QUERY_STRING")) 371 if (getenv("QUERY_STRING"))
372 ctx.qry.raw = xstrdup(getenv("QUERY_STRING")); 372 ctx.qry.raw = xstrdup(getenv("QUERY_STRING"));
373 cgit_parse_args(argc, argv); 373 cgit_parse_args(argc, argv);
374 http_parse_querystring(ctx.qry.raw, querystring_cb); 374 http_parse_querystring(ctx.qry.raw, querystring_cb);
375 375
376 ttl = calc_ttl(); 376 ttl = calc_ttl();
377 ctx.page.expires += ttl*60; 377 ctx.page.expires += ttl*60;
378 if (ctx.cfg.nocache) 378 if (ctx.cfg.nocache)
379 ctx.cfg.cache_size = 0; 379 ctx.cfg.cache_size = 0;
380 err = cache_process(ctx.cfg.cache_size, ctx.cfg.cache_root, 380 err = cache_process(ctx.cfg.cache_size, ctx.cfg.cache_root,
381 ctx.qry.raw, ttl, process_request, &ctx); 381 ctx.qry.raw, ttl, process_request, &ctx);
382 if (err) 382 if (err)
383 cache_log("[cgit] error %d - %s\n", 383 cgit_print_error(fmt("Error processing page: %s (%d)",
384 err, strerror(err)); 384 strerror(err), err));
385 return err; 385 return err;
386} 386}