@@ -169,6 +169,116 @@ bool Fastly::getGeolocationForIpAddress(JSContext *cx, unsigned argc, JS::Value
169169  return  JS_ParseJSON (cx, geo_info_str, args.rval ());
170170}
171171
172+ bool  Fastly::inspect (JSContext *cx, unsigned  argc, JS::Value *vp) {
173+   JS::CallArgs args = CallArgsFromVp (argc, vp);
174+   REQUEST_HANDLER_ONLY (" inspect" 
175+   if  (!args.requireAtLeast (cx, " inspect" 1 )) {
176+     return  false ;
177+   }
178+ 
179+   auto  request_value = args.get (0 );
180+   if  (!Request::is_instance (request_value)) {
181+     JS_ReportErrorUTF8 (cx, " inspect: request parameter must be an instance of Request" 
182+     return  false ;
183+   }
184+   auto  inspect_response_obj = &request_value.toObject ();
185+ 
186+   auto  options_value = args.get (1 );
187+   JS::RootedObject options_obj (cx, options_value.isObject () ? &options_value.toObject () : nullptr );
188+ 
189+   host_api::InspectOptions inspect_options (Request::request_handle (inspect_response_obj),
190+                                            RequestOrResponse::body_handle (inspect_response_obj));
191+ 
192+   if  (options_value != nullptr ) {
193+ 
194+     host_api::HostString corp_str;
195+     JS::RootedValue corp_val (cx);
196+     if  (!JS_GetProperty (cx, options, " corp" 
197+       return  false ;
198+     }
199+     if  (!corp_val.isNullOrUndefined ()) {
200+       if  (!corp_val.isString ()) {
201+         api::throw_error (cx, api::Errors::TypeError, " inspect" " corp" " be a string" 
202+         return  false ;
203+       }
204+       corp_str = core::encode (cx, corp_val);
205+       if  (!corp_str) {
206+         return  false ;
207+       }
208+       std::optional<std::string_view> corp = corp_str;
209+       if  (corp) {
210+         inspect_options.corp_len  = corp->length ();
211+         inspect_options.corp  = std::move (corp->data ());
212+       }
213+     }
214+ 
215+     host_api::HostString workspace_str;
216+     JS::RootedValue workspace_val (cx);
217+     if  (!JS_GetProperty (cx, options, " workspace" 
218+       return  false ;
219+     }
220+     if  (!workspace_val.isNullOrUndefined ()) {
221+       if  (!workspace_val.isString ()) {
222+         api::throw_error (cx, api::Errors::TypeError, " inspect" " workspace" " be a string" 
223+         return  false ;
224+       }
225+       workspace_str = core::encode (cx, workspace_val);
226+       if  (!workspace_str) {
227+         return  false ;
228+       }
229+       std::optional<std::string_view> workspace = workspace_str;
230+       if  (workspace) {
231+         inspect_options.workspace_len  = workspace->length ();
232+         inspect_options.workspace  = std::move (workspace->data ());
233+       }
234+     }
235+ 
236+     host_api::HostString override_client_ip_str;
237+     JS::RootedValue override_client_ip_val (cx);
238+     if  (!JS_GetProperty (cx, options, " overrideClientIp" 
239+       return  false ;
240+     }
241+     if  (!override_client_ip_val.isNullOrUndefined ()) {
242+       if  (!override_client_ip_val.isString ()) {
243+         api::throw_error (cx, api::Errors::TypeError, " fastly.inspect" " overrideClientIp" 
244+                          " be a string" 
245+         return  false ;
246+       }
247+       override_client_ip_str = core::encode (cx, override_client_ip_val);
248+       if  (!override_client_ip_str) {
249+         return  false ;
250+       }
251+ 
252+       //  TODO: Remove all of this and rely on the host for validation as the hostcall only takes one
253+       //  user-supplied parameter
254+       int  format = AF_INET;
255+       size_t  octets_len = 4 ;
256+       if  (std::find (override_client_ip_str.begin (), override_client_ip_str.end (), ' :' 
257+           override_client_ip_str.end ()) {
258+         format = AF_INET6;
259+         octets_len = 16 ;
260+       }
261+ 
262+       uint8_t  octets[sizeof (struct  in6_addr )];
263+       if  (inet_pton (format, override_client_ip_str.begin (), octets) != 1 ) {
264+         api::throw_error (cx, api::Errors::TypeError, " fastly.inspect" " overrideClientIp" 
265+                          " be a valid IP address" 
266+         return  false ;
267+       }
268+       inspect_options.override_client_ip_len  = octets_len;
269+       inspect_options.override_client_ip  = std::move (octets->data ());
270+     }
271+   }
272+ 
273+   auto  res = request_value->inspect (&inspect_options);
274+   if  (auto  *err = res.to_err ()) {
275+     HANDLE_ERROR (cx, *err);
276+     return  false ;
277+   }
278+ 
279+   return  JS_ParseJSON (cx, inspect_info_str, args.rval ());
280+ }
281+ 
172282//  TODO(performance): consider allowing logger creation during initialization, but then throw
173283//  when trying to log.
174284//  https://github.com/fastly/js-compute-runtime/issues/225
@@ -610,6 +720,7 @@ bool install(api::Engine *engine) {
610720      JS_FN (" enableDebugLogging" 1 , JSPROP_ENUMERATE),
611721      JS_FN (" debugLog" 1 , JSPROP_ENUMERATE),
612722      JS_FN (" getGeolocationForIpAddress" 1 , JSPROP_ENUMERATE),
723+       JS_FN (" inspect" 1 , JSPROP_ENUMERATE),
613724      JS_FN (" getLogger" 1 , JSPROP_ENUMERATE),
614725      JS_FN (" includeBytes" 1 , JSPROP_ENUMERATE),
615726      JS_FN (" createFanoutHandoff" 2 , JSPROP_ENUMERATE),
@@ -751,6 +862,21 @@ bool install(api::Engine *engine) {
751862  if  (!engine->define_builtin_module (" fastly:fanout" 
752863    return  false ;
753864  }
865+ 
866+   //  fastly:security
867+   RootedValue inspect_val (engine->cx ());
868+   if  (!JS_GetProperty (engine->cx (), fastly, " inspect" 
869+     return  false ;
870+   }
871+   RootedObject security_builtin (engine->cx (), JS_NewObject (engine->cx (), nullptr ));
872+   RootedValue security_builtin_val (engine->cx (), JS::ObjectValue (*security_builtin));
873+   if  (!JS_SetProperty (engine->cx (), security_builtin, " inspect" 
874+     return  false ;
875+   }
876+   if  (!engine->define_builtin_module (" fastly:security" 
877+     return  false ;
878+   }
879+ 
754880  //  fastly:websocket
755881  RootedObject websocket (engine->cx (), JS_NewObject (engine->cx (), nullptr ));
756882  RootedValue websocket_val (engine->cx (), JS::ObjectValue (*websocket));
0 commit comments