prepareHTTPRequest handles all common request preparation logic shared between SimulateHTTP and SimulateHTTPStreaming: URL decoding, template rendering, body loading, multipart construction, compression, and client creation.
(ctx context.Context, tc *models.TestCase, testSet string, logger *zap.Logger, cfg SimulationConfig)
| 337 | // SimulateHTTP and SimulateHTTPStreaming: URL decoding, template rendering, |
| 338 | // body loading, multipart construction, compression, and client creation. |
| 339 | func prepareHTTPRequest(ctx context.Context, tc *models.TestCase, testSet string, logger *zap.Logger, cfg SimulationConfig) (*preparedHTTPRequest, error) { |
| 340 | // case in which URL string has encoded template placeholders |
| 341 | if strings.Contains(tc.HTTPReq.URL, "%7B") { |
| 342 | decoded, err := url.QueryUnescape(tc.HTTPReq.URL) |
| 343 | if err == nil { |
| 344 | tc.HTTPReq.URL = decoded |
| 345 | } |
| 346 | } |
| 347 | |
| 348 | // TODO: adjust this logic in the render function in order to remove the redundant code. |
| 349 | // Convert testcase to string and render template values before simulation. |
| 350 | templateData := buildTemplateDataSnapshot() |
| 351 | if len(templateData) > 0 { |
| 352 | testCaseBytes, err := json.Marshal(tc) |
| 353 | if err != nil { |
| 354 | utils.LogError(logger, err, "failed to marshal the testcase for templating") |
| 355 | return nil, err |
| 356 | } |
| 357 | |
| 358 | // Render only real Keploy placeholders ({{ .x }}, {{ string .y }}, etc.), |
| 359 | // ignoring LaTeX/HTML like {{\pi}}. |
| 360 | renderedStr, rerr := utils.RenderTemplatesInString(logger, string(testCaseBytes), templateData) |
| 361 | if rerr != nil { |
| 362 | logger.Debug("template rendering had recoverable errors", zap.Error(rerr)) |
| 363 | } |
| 364 | |
| 365 | err = json.Unmarshal([]byte(renderedStr), &tc) |
| 366 | if err != nil { |
| 367 | utils.LogError(logger, err, "failed to unmarshal the rendered testcase") |
| 368 | return nil, err |
| 369 | } |
| 370 | } |
| 371 | |
| 372 | reqBody := []byte(tc.HTTPReq.Body) |
| 373 | var err error |
| 374 | |
| 375 | // If the request body was offloaded to an asset file (>1MB), load it back |
| 376 | if tc.HTTPReq.BodyRef.Path != "" { |
| 377 | bodyRefPath := tc.HTTPReq.BodyRef.Path |
| 378 | // Resolve relative paths against keployPath so assets work even if |
| 379 | // the keploy directory has been moved since recording. |
| 380 | if cfg.KeployPath != "" && !filepath.IsAbs(bodyRefPath) { |
| 381 | bodyRefPath = filepath.Join(cfg.KeployPath, bodyRefPath) |
| 382 | } |
| 383 | bodyData, readErr := os.ReadFile(bodyRefPath) |
| 384 | if readErr != nil { |
| 385 | utils.LogError(logger, readErr, "failed to read request body from asset file", zap.String("path", bodyRefPath)) |
| 386 | return nil, readErr |
| 387 | } |
| 388 | reqBody = bodyData |
| 389 | logger.Debug("loaded request body from asset file", |
| 390 | zap.String("path", bodyRefPath), |
| 391 | zap.Int("size", len(bodyData))) |
| 392 | } |
| 393 | |
| 394 | // If form field values were offloaded to asset files (>1MB) and they were not actual files (json,html,xml,txt etc...), load them back |
| 395 | for i, form := range tc.HTTPReq.Form { |
| 396 | if len(form.FileNames) == 0 && len(form.Paths) > 0 && len(form.Values) > 0 { |
no test coverage detected