@@ -156,6 +156,63 @@ static int ConvertListEntryToMap(const list_entry_t& list_entry, const duckdb::V
156156 return result.size ();
157157}
158158
159+
160+
161+ std::string headers_to_string (const duckdb_httplib_openssl::Headers& headers) {
162+ std::string result = " {" ;
163+
164+ for (const auto & pair : headers) {
165+ const std::string& key = pair.first ;
166+ const std::string& value = pair.second ;
167+
168+ std::string lower_key = key;
169+ std::transform (lower_key.begin (), lower_key.end (), lower_key.begin (),
170+ [](unsigned char c){ return std::tolower (c); });
171+
172+ result += " \" " + escape_json (lower_key) + " \" :\" " + escape_json (value) + " \" ," ;
173+ }
174+
175+ if (result.length () > 1 ) {
176+ result.pop_back (); // Remove trailing comma
177+ }
178+ result += " }" ;
179+
180+ return result;
181+ }
182+
183+
184+ static void HTTPHeadRequestFunction (DataChunk &args, ExpressionState &state, Vector &result) {
185+ D_ASSERT (args.data .size () == 1 );
186+
187+ UnaryExecutor::Execute<string_t , string_t >(args.data [0 ], result, args.size (), [&](string_t input) {
188+ std::string url = input.GetString ();
189+
190+ // Use helper to setup client and parse URL
191+ auto client_and_path = SetupHttpClient (url);
192+ auto &client = client_and_path.first ;
193+ auto &path = client_and_path.second ;
194+
195+ // Make the HEAD request
196+ auto res = client.Head (path.c_str ());
197+ if (res) {
198+ auto headers = headers_to_string (res->headers );
199+ std::string response = StringUtil::Format (
200+ " { \" status\" : %i, \" reason\" : \" %s\" , \" headers\" : \" %s\" }" ,
201+ res->status ,
202+ escape_json (res->reason ),
203+ escape_json (headers)
204+ );
205+ return StringVector::AddString (result, response);
206+ } else {
207+ std::string response = StringUtil::Format (
208+ " { \" status\" : %i, \" reason\" : \" %s\" , \" headers\" : \" %s\" }" ,
209+ -1 , GetHttpErrorMessage (res, " HEAD" ), " "
210+ );
211+ return StringVector::AddString (result, response);
212+ }
213+ });
214+ }
215+
159216static void HTTPGetRequestFunction (DataChunk &args, ExpressionState &state, Vector &result) {
160217 D_ASSERT (args.data .size () == 1 );
161218
@@ -303,6 +360,10 @@ static void HTTPPostFormRequestFunction(DataChunk &args, ExpressionState &state,
303360
304361
305362static void LoadInternal (DatabaseInstance &instance) {
363+ ScalarFunctionSet http_head (" http_head" );
364+ http_head.AddFunction (ScalarFunction ({LogicalType::VARCHAR}, LogicalType::JSON (), HTTPHeadRequestFunction));
365+ ExtensionUtil::RegisterFunction (instance, http_head);
366+
306367 ScalarFunctionSet http_get (" http_get" );
307368 http_get.AddFunction (ScalarFunction ({LogicalType::VARCHAR}, LogicalType::JSON (), HTTPGetRequestFunction));
308369 http_get.AddFunction (ScalarFunction (
@@ -358,4 +419,3 @@ DUCKDB_EXTENSION_API const char *http_client_version() {
358419#ifndef DUCKDB_EXTENSION_MAIN
359420#error DUCKDB_EXTENSION_MAIN not defined
360421#endif
361-
0 commit comments