My agentic slop goes here. Not intended for anyone else!

nocache

Changed files
+11 -553
stack
+5 -13
stack/requests/bin/ocurl.ml
···
let doc = "Show progress bar for downloads" in
Arg.(value & flag & info ["progress-bar"] ~doc)
-
let enable_cache =
-
let doc = "Enable HTTP response caching for GET and HEAD requests" in
-
let env_info = Cmdliner.Cmd.Env.info "OCURL_ENABLE_CACHE" in
-
Arg.(value & flag & info ["enable-cache"] ~env:env_info ~doc)
-
(* Logging setup *)
(* Setup logging using Logs_cli for standard logging options *)
let setup_log =
···
Error (url_str, exn)
(* Main function using Requests with concurrent fetching *)
-
let run_request env sw persist_cookies verify_tls enable_cache timeout follow_redirects max_redirects
+
let run_request env sw persist_cookies verify_tls timeout follow_redirects max_redirects
method_ urls headers data json_data output include_headers
auth _show_progress () =
···
(* Create requests instance with configuration *)
let timeout_obj = Option.map (fun t -> Requests.Timeout.create ~total:t ()) timeout in
-
let req = Requests.create ~sw ~xdg ~persist_cookies ~verify_tls ~enable_cache
+
let req = Requests.create ~sw ~xdg ~persist_cookies ~verify_tls
~follow_redirects ~max_redirects ?timeout:timeout_obj env in
(* Set authentication if provided *)
···
(* Main entry point *)
let main method_ urls headers data json_data output include_headers
-
auth show_progress persist_cookies verify_tls enable_cache
+
auth show_progress persist_cookies verify_tls
timeout follow_redirects max_redirects () =
Eio_main.run @@ fun env ->
Mirage_crypto_rng_unix.use_default ();
Switch.run @@ fun sw ->
-
run_request env sw persist_cookies verify_tls enable_cache timeout follow_redirects max_redirects
+
run_request env sw persist_cookies verify_tls timeout follow_redirects max_redirects
method_ urls headers data json_data output include_headers auth
show_progress ()
···
`P "Custom headers:";
`Pre " $(tname) -H 'Accept: application/json' -H 'X-Api-Key: secret' https://api.example.com";
`P "With persistent cookies:";
-
`Pre " $(tname) --persist-cookies --cache-dir ~/.ocurl https://example.com";
-
`P "Enable response caching:";
-
`Pre " $(tname) --enable-cache https://api.example.com";
+
`Pre " $(tname) --persist-cookies https://example.com";
`P "Disable TLS verification (insecure):";
`Pre " $(tname) --no-verify-tls https://self-signed.example.com";
`S "LOGGING OPTIONS";
···
show_progress $
Requests.Cmd.persist_cookies_term app_name $
Requests.Cmd.verify_tls_term app_name $
-
enable_cache $
Requests.Cmd.timeout_term app_name $
Requests.Cmd.follow_redirects_term app_name $
Requests.Cmd.max_redirects_term app_name $
-488
stack/requests/lib/cache.ml
···
-
let src = Logs.Src.create "requests.cache" ~doc:"HTTP cache with cacheio"
-
module Log = (val Logs.src_log src : Logs.LOG)
-
-
type cached_response = {
-
status : Cohttp.Code.status_code;
-
headers : Cohttp.Header.t;
-
body : string;
-
}
-
-
type t = {
-
sw : Eio.Switch.t;
-
enabled : bool;
-
cache_get_requests : bool;
-
cache_range_requests : bool;
-
cacheio : Cacheio.t option;
-
memory_cache : (string, cached_response * float) Hashtbl.t;
-
}
-
-
let create ~sw ~enabled ?(cache_get_requests=true) ?(cache_range_requests=true) ~cache_dir () =
-
let cacheio =
-
match cache_dir with
-
| Some dir when enabled ->
-
(try
-
Some (Cacheio.create ~base_dir:dir)
-
with e ->
-
Log.warn (fun m -> m "Failed to create cacheio backend: %s. Using memory cache only."
-
(Printexc.to_string e));
-
None)
-
| _ -> None
-
in
-
{ sw; enabled; cache_get_requests; cache_range_requests; cacheio;
-
memory_cache = Hashtbl.create 100 }
-
-
let make_cache_key ~method_ ~url ~headers =
-
let method_str = match method_ with
-
| `GET -> "GET" | `HEAD -> "HEAD"
-
| _ -> "OTHER"
-
in
-
let url_str = Uri.to_string url in
-
let range_str = match Cohttp.Header.get headers "range" with
-
| Some r -> "_range:" ^ r
-
| None -> ""
-
in
-
Printf.sprintf "%s_%s%s" method_str url_str range_str
-
-
let is_cacheable ~method_ ~status ~headers =
-
match method_ with
-
| `GET | `HEAD ->
-
let code = Cohttp.Code.code_of_status status in
-
if code >= 200 && code < 300 then
-
match Cohttp.Header.get headers "cache-control" with
-
| Some cc ->
-
let cc_lower = String.lowercase_ascii cc in
-
let rec contains s sub pos =
-
if pos + String.length sub > String.length s then false
-
else if String.sub s pos (String.length sub) = sub then true
-
else contains s sub (pos + 1)
-
in
-
not (contains cc_lower "no-store" 0 ||
-
contains cc_lower "no-cache" 0 ||
-
contains cc_lower "private" 0)
-
| None -> true
-
else
-
code = 301 || code = 308
-
| _ -> false
-
-
let parse_max_age headers =
-
match Cohttp.Header.get headers "cache-control" with
-
| Some cc ->
-
let parts = String.split_on_char ',' cc |> List.map String.trim in
-
List.find_map (fun part ->
-
let prefix = "max-age=" in
-
if String.starts_with ~prefix part then
-
let value = String.sub part (String.length prefix)
-
(String.length part - String.length prefix) in
-
try Some (float_of_string value) with _ -> None
-
else None
-
) parts
-
| None -> None
-
-
(* JSON codec for cache metadata *)
-
module Metadata = struct
-
type t = {
-
status_code : int;
-
headers : (string * string) list;
-
}
-
-
let make status_code headers = { status_code; headers }
-
let status_code t = t.status_code
-
let headers t = t.headers
-
-
let t_jsont =
-
let header_pair_jsont =
-
let dec x y = (x, y) in
-
let enc (x, y) i = if i = 0 then x else y in
-
Jsont.t2 ~dec ~enc Jsont.string
-
in
-
Jsont.Object.map ~kind:"CacheMetadata" make
-
|> Jsont.Object.mem "status_code" Jsont.int ~enc:status_code
-
|> Jsont.Object.mem "headers" (Jsont.list header_pair_jsont) ~enc:headers
-
|> Jsont.Object.finish
-
end
-
-
let serialize_metadata ~status ~headers =
-
let status_code = Cohttp.Code.code_of_status status in
-
let headers_assoc = Cohttp.Header.to_list headers in
-
let metadata = Metadata.make status_code headers_assoc in
-
match Jsont_bytesrw.encode_string' Metadata.t_jsont metadata with
-
| Ok s -> s
-
| Error e -> failwith (Fmt.str "Failed to serialize metadata: %s" (Jsont.Error.to_string e))
-
-
let deserialize_metadata json_str =
-
try
-
match Jsont_bytesrw.decode_string' Metadata.t_jsont json_str with
-
| Ok metadata ->
-
let status = Cohttp.Code.status_of_code (Metadata.status_code metadata) in
-
let headers = Cohttp.Header.of_list (Metadata.headers metadata) in
-
Some (status, headers)
-
| Error _ -> None
-
with _ -> None
-
-
let get t ~method_ ~url ~headers =
-
if not t.enabled then None
-
else if method_ = `GET && not t.cache_get_requests then None
-
else
-
let key = make_cache_key ~method_ ~url ~headers in
-
-
(* Try cacheio first *)
-
match t.cacheio with
-
| Some cache ->
-
(* Check for metadata entry *)
-
let metadata_key = key ^ ".meta" in
-
let body_key = key ^ ".body" in
-
-
if Cacheio.exists cache ~key:metadata_key && Cacheio.exists cache ~key:body_key then
-
Eio.Switch.run @@ fun sw ->
-
(* Read metadata *)
-
let metadata_opt = match Cacheio.get cache ~key:metadata_key ~sw with
-
| Some source ->
-
let buf = Buffer.create 256 in
-
Eio.Flow.copy source (Eio.Flow.buffer_sink buf);
-
deserialize_metadata (Buffer.contents buf)
-
| None -> None
-
in
-
-
(match metadata_opt with
-
| Some (status, resp_headers) ->
-
(* Read body *)
-
(match Cacheio.get cache ~key:body_key ~sw with
-
| Some source ->
-
let buf = Buffer.create 4096 in
-
Eio.Flow.copy source (Eio.Flow.buffer_sink buf);
-
let body = Buffer.contents buf in
-
Log.debug (fun m -> m "Cache hit for %s" (Uri.to_string url));
-
Some { status; headers = resp_headers; body }
-
| None ->
-
Log.debug (fun m -> m "Cache body missing for %s" (Uri.to_string url));
-
None)
-
| None ->
-
Log.debug (fun m -> m "Cache metadata missing for %s" (Uri.to_string url));
-
None)
-
else
-
(Log.debug (fun m -> m "Cache miss for %s" (Uri.to_string url));
-
None)
-
| None ->
-
(* Fall back to memory cache *)
-
match Hashtbl.find_opt t.memory_cache key with
-
| Some (response, expiry) when expiry > Unix.gettimeofday () ->
-
Log.debug (fun m -> m "Memory cache hit for %s" (Uri.to_string url));
-
Some response
-
| _ ->
-
Log.debug (fun m -> m "Cache miss for %s" (Uri.to_string url));
-
None
-
-
let get_stream t ~method_ ~url ~headers ~sw =
-
if not t.enabled then None
-
else if method_ = `GET && not t.cache_get_requests then None
-
else
-
let key = make_cache_key ~method_ ~url ~headers in
-
-
match t.cacheio with
-
| Some cache ->
-
let metadata_key = key ^ ".meta" in
-
let body_key = key ^ ".body" in
-
-
if Cacheio.exists cache ~key:metadata_key && Cacheio.exists cache ~key:body_key then
-
(* Read metadata first *)
-
let metadata_opt =
-
match Cacheio.get cache ~key:metadata_key ~sw with
-
| Some source ->
-
let buf = Buffer.create 256 in
-
Eio.Flow.copy source (Eio.Flow.buffer_sink buf);
-
deserialize_metadata (Buffer.contents buf)
-
| None -> None
-
in
-
-
(match metadata_opt with
-
| Some (status, resp_headers) ->
-
(* Return body stream directly *)
-
(match Cacheio.get cache ~key:body_key ~sw with
-
| Some source ->
-
Log.debug (fun m -> m "Streaming cache hit for %s" (Uri.to_string url));
-
Some (status, resp_headers, source)
-
| None -> None)
-
| None -> None)
-
else None
-
| None -> None
-
-
let put t ~method_ ~url ~request_headers ~status ~headers ~body =
-
if not t.enabled then ()
-
else if is_cacheable ~method_ ~status ~headers then
-
let key = make_cache_key ~method_ ~url ~headers:request_headers in
-
let ttl = parse_max_age headers in
-
-
Log.debug (fun m -> m "Caching response for %s (ttl: %s)"
-
(Uri.to_string url)
-
(match ttl with Some t -> Printf.sprintf "%.0fs" t | None -> "3600s"));
-
-
(match t.cacheio with
-
| Some cache ->
-
Eio.Switch.run @@ fun _sw ->
-
let metadata_key = key ^ ".meta" in
-
let metadata = serialize_metadata ~status ~headers in
-
let metadata_source = Eio.Flow.string_source metadata in
-
Cacheio.put cache ~key:metadata_key ~source:metadata_source ~ttl ();
-
-
let body_key = key ^ ".body" in
-
let body_source = Eio.Flow.string_source body in
-
Cacheio.put cache ~key:body_key ~source:body_source ~ttl ()
-
| None -> ());
-
-
let cached_resp = { status; headers; body } in
-
let expiry = Unix.gettimeofday () +. Option.value ttl ~default:3600.0 in
-
Hashtbl.replace t.memory_cache key (cached_resp, expiry)
-
-
let put_stream t ~method_ ~url ~request_headers ~status ~headers ~body_source ~ttl =
-
if not t.enabled then ()
-
else if is_cacheable ~method_ ~status ~headers then
-
let key = make_cache_key ~method_ ~url ~headers:request_headers in
-
-
Log.debug (fun m -> m "Caching streamed response for %s (ttl: %s)"
-
(Uri.to_string url)
-
(match ttl with Some t -> Printf.sprintf "%.0fs" t | None -> "3600s"));
-
-
match t.cacheio with
-
| Some cache ->
-
Eio.Switch.run @@ fun _sw ->
-
-
(* Store metadata *)
-
let metadata_key = key ^ ".meta" in
-
let metadata = serialize_metadata ~status ~headers in
-
let metadata_source = Eio.Flow.string_source metadata in
-
Cacheio.put cache ~key:metadata_key ~source:metadata_source ~ttl ();
-
-
(* Store body directly from source *)
-
let body_key = key ^ ".body" in
-
Cacheio.put cache ~key:body_key ~source:body_source ~ttl ()
-
| None -> ()
-
-
module Range = struct
-
type t = {
-
start : int64;
-
end_ : int64 option; (* None means to end of file *)
-
}
-
-
let of_header header =
-
(* Parse Range: bytes=start-end *)
-
let prefix = "bytes=" in
-
let prefix_len = String.length prefix in
-
if String.length header >= prefix_len &&
-
String.sub header 0 prefix_len = prefix then
-
let range_str = String.sub header prefix_len (String.length header - prefix_len) in
-
match String.split_on_char '-' range_str with
-
| [start; ""] ->
-
(* bytes=N- means from N to end *)
-
(try Some { start = Int64.of_string start; end_ = None }
-
with _ -> None)
-
| [start; end_] ->
-
(* bytes=N-M *)
-
(try Some {
-
start = Int64.of_string start;
-
end_ = Some (Int64.of_string end_)
-
}
-
with _ -> None)
-
| _ -> None
-
else None
-
-
let to_header t =
-
match t.end_ with
-
| None -> Printf.sprintf "bytes=%Ld-" t.start
-
| Some e -> Printf.sprintf "bytes=%Ld-%Ld" t.start e
-
-
let to_cacheio_range t ~total_size =
-
let end_ = match t.end_ with
-
| None -> Int64.pred total_size
-
| Some e -> min e (Int64.pred total_size)
-
in
-
(* Convert to Cacheio.Range.t *)
-
Cacheio.Range.create ~start:t.start ~end_
-
end
-
-
let download_range t ~sw ~url ~range ~on_chunk =
-
let range_header = Range.to_header range in
-
Log.debug (fun m -> m "Range request for %s: %s"
-
(Uri.to_string url) range_header);
-
-
match t.cacheio with
-
| Some cache ->
-
let key = Uri.to_string url in
-
let cacheio_range = Range.to_cacheio_range range ~total_size:Int64.max_int in
-
-
(match Cacheio.get_range cache ~key ~range:cacheio_range ~sw with
-
| `Complete source ->
-
let rec read_chunks () =
-
let chunk = Cstruct.create 8192 in
-
try
-
let n = Eio.Flow.single_read source chunk in
-
if n > 0 then begin
-
on_chunk (Cstruct.to_string ~off:0 ~len:n chunk);
-
read_chunks ()
-
end
-
with End_of_file -> ()
-
in
-
read_chunks ();
-
Some true
-
| `Chunks chunk_sources ->
-
List.iter (fun (_range, source) ->
-
let rec read_chunk () =
-
let chunk = Cstruct.create 8192 in
-
try
-
let n = Eio.Flow.single_read source chunk in
-
if n > 0 then begin
-
on_chunk (Cstruct.to_string ~off:0 ~len:n chunk);
-
read_chunk ()
-
end
-
with End_of_file -> ()
-
in
-
read_chunk ()
-
) chunk_sources;
-
Some true
-
| `Not_found -> None)
-
| None -> None
-
-
let put_chunk t ~url ~range ~data =
-
if not t.enabled || not t.cache_range_requests then ()
-
else
-
match t.cacheio with
-
| Some cache ->
-
let key = Uri.to_string url in
-
let cacheio_range = Range.to_cacheio_range range ~total_size:Int64.max_int in
-
Eio.Switch.run @@ fun _sw ->
-
let source = Eio.Flow.string_source data in
-
Cacheio.put_chunk cache ~key ~range:cacheio_range ~source ()
-
| None ->
-
Log.debug (fun m -> m "Cannot cache chunk for %s: no cacheio backend"
-
(Uri.to_string url))
-
-
let has_complete t ~url ~total_size =
-
if not t.enabled then false
-
else
-
match t.cacheio with
-
| Some cache ->
-
let key = Uri.to_string url in
-
Cacheio.has_complete_chunks cache ~key ~total_size
-
| None -> false
-
-
let missing_ranges t ~url ~total_size =
-
if not t.enabled then
-
[{ Range.start = 0L; end_ = Some (Int64.pred total_size) }]
-
else
-
match t.cacheio with
-
| Some cache ->
-
let key = Uri.to_string url in
-
let cacheio_ranges = Cacheio.missing_ranges cache ~key ~total_size in
-
List.map (fun r ->
-
{ Range.start = Cacheio.Range.start r;
-
end_ = Some (Cacheio.Range.end_ r) }
-
) cacheio_ranges
-
| None ->
-
[{ Range.start = 0L; end_ = Some (Int64.pred total_size) }]
-
-
let coalesce_chunks t ~url =
-
if not t.enabled then false
-
else
-
match t.cacheio with
-
| Some cache ->
-
let key = Uri.to_string url in
-
let promise = Cacheio.coalesce_chunks cache ~key ~verify:true () in
-
(match Eio.Promise.await promise with
-
| Ok () ->
-
Log.info (fun m -> m "Successfully coalesced chunks for %s" key);
-
true
-
| Error exn ->
-
Log.warn (fun m -> m "Failed to coalesce chunks for %s: %s"
-
key (Printexc.to_string exn));
-
false)
-
| None -> false
-
-
let evict t ~url =
-
if not t.enabled then ()
-
else
-
let key = make_cache_key ~method_:`GET ~url ~headers:(Cohttp.Header.init ()) in
-
(match t.cacheio with
-
| Some cache ->
-
Cacheio.delete cache ~key:(key ^ ".meta");
-
Cacheio.delete cache ~key:(key ^ ".body")
-
| None -> ());
-
Log.debug (fun m -> m "Evicting cache for %s" (Uri.to_string url));
-
Hashtbl.remove t.memory_cache key
-
-
let clear t =
-
Log.info (fun m -> m "Clearing entire cache");
-
(match t.cacheio with
-
| Some cache -> Cacheio.clear cache
-
| None -> ());
-
Hashtbl.clear t.memory_cache
-
-
module Stats = struct
-
type cacheio_stats = {
-
total_entries : int;
-
total_bytes : int;
-
expired_entries : int;
-
pinned_entries : int;
-
temporary_entries : int;
-
}
-
-
type t = {
-
memory_cache_entries : int;
-
cache_backend : string;
-
enabled : bool;
-
cache_get_requests : bool;
-
cache_range_requests : bool;
-
cacheio_stats : cacheio_stats option;
-
}
-
-
let make_cacheio_stats total_entries total_bytes expired_entries pinned_entries temporary_entries =
-
{ total_entries; total_bytes; expired_entries; pinned_entries; temporary_entries }
-
-
let make memory_cache_entries cache_backend enabled cache_get_requests cache_range_requests cacheio_stats =
-
{ memory_cache_entries; cache_backend; enabled; cache_get_requests; cache_range_requests; cacheio_stats }
-
-
let cacheio_stats_jsont =
-
Jsont.Object.map ~kind:"CacheioStats" make_cacheio_stats
-
|> Jsont.Object.mem "total_entries" Jsont.int ~enc:(fun t -> t.total_entries)
-
|> Jsont.Object.mem "total_bytes" Jsont.int ~enc:(fun t -> t.total_bytes)
-
|> Jsont.Object.mem "expired_entries" Jsont.int ~enc:(fun t -> t.expired_entries)
-
|> Jsont.Object.mem "pinned_entries" Jsont.int ~enc:(fun t -> t.pinned_entries)
-
|> Jsont.Object.mem "temporary_entries" Jsont.int ~enc:(fun t -> t.temporary_entries)
-
|> Jsont.Object.finish
-
-
let t_jsont =
-
Jsont.Object.map ~kind:"CacheStats" make
-
|> Jsont.Object.mem "memory_cache_entries" Jsont.int ~enc:(fun t -> t.memory_cache_entries)
-
|> Jsont.Object.mem "cache_backend" Jsont.string ~enc:(fun t -> t.cache_backend)
-
|> Jsont.Object.mem "enabled" Jsont.bool ~enc:(fun t -> t.enabled)
-
|> Jsont.Object.mem "cache_get_requests" Jsont.bool ~enc:(fun t -> t.cache_get_requests)
-
|> Jsont.Object.mem "cache_range_requests" Jsont.bool ~enc:(fun t -> t.cache_range_requests)
-
|> Jsont.Object.opt_mem "cacheio_stats" cacheio_stats_jsont ~enc:(fun t -> t.cacheio_stats)
-
|> Jsont.Object.finish
-
-
let to_string t =
-
match Jsont_bytesrw.encode_string' ~format:Jsont.Indent t_jsont t with
-
| Ok s -> s
-
| Error e ->
-
let msg = Jsont.Error.to_string e in
-
failwith (Printf.sprintf "Failed to encode stats: %s" msg)
-
end
-
-
let stats t =
-
let cacheio_stats =
-
match t.cacheio with
-
| Some cache ->
-
let stats = Cacheio.stats cache in
-
Some (Stats.make_cacheio_stats
-
(Cacheio.Stats.entry_count stats)
-
(Int64.to_int (Cacheio.Stats.total_size stats))
-
(Cacheio.Stats.expired_count stats)
-
(Cacheio.Stats.pinned_count stats)
-
(Cacheio.Stats.temporary_count stats))
-
| None -> None
-
in
-
Stats.make
-
(Hashtbl.length t.memory_cache)
-
(if Option.is_some t.cacheio then "cacheio" else "memory")
-
t.enabled
-
t.cache_get_requests
-
t.cache_range_requests
-
cacheio_stats
-1
stack/requests/lib/dune
···
jsont
jsont.bytesrw
base64
-
cacheio
cookeio
xdge
logs
+2 -45
stack/requests/lib/requests.ml
···
module Status = Status
module Error = Error
module Retry = Retry
-
module Cache = Cache
(* Note: RNG initialization should be done by the application using
Mirage_crypto_rng_unix.initialize before calling Eio_main.run.
···
retry : Retry.config option;
persist_cookies : bool;
xdg : Xdge.t option;
-
cache : Cache.t option;
(* Statistics - mutable for tracking across all derived sessions *)
mutable requests_made : int;
···
?(connection_lifetime = 300.0)
?retry
?(persist_cookies = false)
-
?(enable_cache = false)
?xdg
env =
let clock = env#clock in
let net = env#net in
-
let xdg = match xdg, persist_cookies || enable_cache with
+
let xdg = match xdg, persist_cookies with
| Some x, _ -> Some x
| None, true -> Some (Xdge.create env#fs "requests")
| None, false -> None
···
Cookeio.create ()
in
-
let cache = match enable_cache, xdg with
-
| true, Some xdg_ctx ->
-
let cache_dir = Xdge.cache_dir xdg_ctx in
-
Some (Cache.create ~sw ~enabled:true ~cache_dir:(Some cache_dir) ())
-
| true, None ->
-
(* Memory-only cache when no XDG available *)
-
Some (Cache.create ~sw ~enabled:true ~cache_dir:None ())
-
| false, _ -> None
-
in
-
{
sw;
clock;
···
retry;
persist_cookies;
xdg;
-
cache;
requests_made = 0;
total_time = 0.0;
retries_count = 0;
···
| Some b -> Body.Private.to_string b
in
-
(* Check cache for GET and HEAD requests when body is not present *)
-
let cached_response = match t.cache, method_, body with
-
| Some cache, (`GET | `HEAD), None ->
-
Log.debug (fun m -> m "Checking cache for %s request to %s" method_str url);
-
let headers_cohttp = Cohttp.Header.of_list (Headers.to_list headers) in
-
Cache.get cache ~method_ ~url:uri ~headers:headers_cohttp
-
| _ -> None
-
in
-
-
let response = match cached_response with
-
| Some cached ->
-
Log.info (fun m -> m "Cache HIT for %s request to %s" method_str url);
-
(* Convert cached response to Response.t *)
-
let status = Cohttp.Code.code_of_status cached.Cache.status in
-
let resp_headers = Headers.of_list (Cohttp.Header.to_list cached.Cache.headers) in
-
let body_flow = Eio.Flow.string_source cached.Cache.body in
-
Response.Private.make ~sw:t.sw ~status ~headers:resp_headers ~body:body_flow ~url ~elapsed:0.0
-
| None ->
-
Log.info (fun m -> m "Cache MISS or not applicable for %s request to %s" method_str url);
+
let response =
(* Execute request with redirect handling *)
let rec make_with_redirects url_to_fetch redirects_left =
···
let elapsed = Unix.gettimeofday () -. start_time in
Log.info (fun m -> m "Request completed in %.3f seconds" elapsed);
-
-
(* Store in cache if successful and caching enabled *)
-
(match t.cache with
-
| Some cache when final_status >= 200 && final_status < 300 ->
-
Log.debug (fun m -> m "Storing response in cache for %s" url);
-
let status = Cohttp.Code.status_of_code final_status in
-
let resp_headers_cohttp = Cohttp.Header.of_list (Headers.to_list final_headers) in
-
let headers_cohttp = Cohttp.Header.of_list (Headers.to_list headers) in
-
Cache.put cache ~method_ ~url:uri ~request_headers:headers_cohttp
-
~status ~headers:resp_headers_cohttp ~body:final_body_str
-
| _ -> ());
(* Create a flow from the body string *)
let body_flow = Eio.Flow.string_source final_body_str in
+4 -6
stack/requests/lib/requests.mli
···
?connection_lifetime:float ->
?retry:Retry.config ->
?persist_cookies:bool ->
-
?enable_cache:bool ->
?xdg:Xdge.t ->
< clock: 'clock Eio.Resource.t; net: 'net Eio.Resource.t; fs: Eio.Fs.dir_ty Eio.Path.t; .. > ->
('clock Eio.Resource.t, 'net Eio.Resource.t) t
···
@param connection_lifetime Max lifetime of any pooled connection (default: 300s)
@param retry Retry configuration for failed requests
@param persist_cookies Whether to persist cookies to disk (default: false)
-
@param enable_cache Whether to enable HTTP caching (default: false)
-
@param xdg XDG directory context for cookies/cache (required if persist_cookies or enable_cache)
+
@param xdg XDG directory context for cookies (required if persist_cookies=true)
+
+
{b Note:} HTTP caching has been disabled for simplicity. See CACHEIO.md for integration notes
+
if you need to restore caching functionality in the future.
*)
(** {2 Configuration Management} *)
···
(** Timeout configuration for requests *)
module Timeout = Timeout
-
-
(** HTTP caching with cache control and range request support *)
-
module Cache = Cache
(** {2 Logging} *)