Computing FoundationsHow the Internet Works › Day 18

Hands-on lab — Day 18: HTTP: Requests, Responses, and Methods

Commands

Setup

cd labs/sections/computing-foundations/day-018-http-requests-responses-and-methods

Run

bash examples/http_explorer.sh
bash starter/http_explorer.sh

Test

bash tests/run_tests.sh

File tree

examples/http_explorer.sh
expected-output/FIELDS.md
expected-output/sample-run.txt
metadata.yml
README.md
requirements/README.md
security.md
starter/http_explorer.sh
starter/http-worksheet.md
tests/run_tests.sh
troubleshooting.md

Lab README

Day 018 lab — Speak HTTP by Hand

Lesson

Purpose

Day 18's lesson reads the two HTTP messages on paper. This lab makes them real: you use curl to send actual requests to free public test services and read the raw request and response — the status line, the headers, the body echoed back. By the end, a status code stops being a mystery and becomes information you act on, which is exactly the skill that turns a failing API call into a two-minute fix.

Learning objectives

  • Send an HTTP request with curl and read both the request (>) and response (<) in verbose mode.
  • Print a bare status code, ignoring the body, with -o /dev/null -w "%{http_code}".
  • Send a POST with a JSON body and confirm the server received it by reading the echo.
  • Trigger a 404 on purpose and classify it (4xx = your request was wrong).
  • Explain, for a 401 versus a 429, whose fault it is and what your code should do.

Prerequisites

  • The Day 18 lesson (read it first — it explains every message this lab sends).
  • Comfort running commands in a terminal (Days 8–14).
  • curl (preinstalled on macOS and Linux) and a working internet connection.

Supported operating systems

  • macOS — fully supported (tested on macOS with curl 8.7.1).
  • Linux — fully supported (any distribution with curl and bash).
  • Windows — use WSL (Windows Subsystem for Linux) and follow the Linux path; curl also ships with modern PowerShell but the flags differ, so WSL is smoother.

Hardware requirements

Any computer that can reach the internet. The lab sends a handful of tiny requests and needs no special hardware.

Required software

  • bash (3.2 or newer — preinstalled on macOS and Linux).
  • curl (preinstalled on macOS and Linux; the one tool this lab depends on).
  • Optional: HTTPie (http) for the friendlier alternative shown in the lesson.

Free and open-source options

Everything here is free. curl is open source and ships with your OS; the test services (https://httpbin.org and its mirror https://httpbingo.org, plus https://example.com) are free public endpoints that need no account or API key. No purchase is required at any point.

Installation

None beyond what your OS already has. From the repository root:

cd labs/sections/computing-foundations/day-018-http-requests-responses-and-methods

If curl is somehow missing, install it with your Day 13 package manager (brew install curl on macOS, sudo apt install curl on Debian/Ubuntu).

File structure

day-018-http-requests-responses-and-methods/
├── README.md                       ← you are here
├── metadata.yml                    ← machine-readable lab metadata
├── starter/
│   ├── http_explorer.sh            ← YOUR working file (4 exercises)
│   └── http-worksheet.md           ← worksheet for the practice assignment
├── examples/
│   └── http_explorer.sh            ← completed reference implementation
├── tests/
│   └── run_tests.sh                ← automated checks (structure + network)
├── expected-output/
│   ├── sample-run.txt              ← a real captured run
│   └── FIELDS.md                   ← what a correct run shows on any platform
├── requirements/
│   └── README.md                   ← dependency statement (just curl)
├── troubleshooting.md
└── security.md

How to run

From this directory:

## 1. See the finished result first
bash examples/http_explorer.sh

## 2. Your task: complete the four exercises in the starter, then run it
bash starter/http_explorer.sh

## 3. Check your work
bash tests/run_tests.sh

What the commands do

  • bash examples/http_explorer.sh — the reference script. It probes the network, then (Step 1) runs curl -v https://example.com and shows the request/response lines, (Step 2) prints just the 200 status code, (Step 3) POSTs {"hello":"world"} and shows the server echoing it back in its json field, and (Step 4) requests a 404 on purpose and prints the code. If httpbin.org is busy it falls back to the compatible mirror httpbingo.org; if there is no network it explains what each step would show and exits cleanly.
  • bash starter/http_explorer.sh — the same skeleton with the four curl commands left as placeholder lines; each exercise comment names the exact command to paste in. Edit the file in any text editor.
  • bash tests/run_tests.sh — runs structure checks always, and network checks (a real 200 from example.com and a real POST echo) when online, skipping them with a clear message when offline. Exits 0 unless a check that actually ran failed.

Expected output

See expected-output/sample-run.txt — a real captured run. The essentials:

STEP 2 — status code only for https://example.com
Status code: 200
...
STEP 3 — POST a JSON body ...
  "json": {
    "hello": "world"
  }
...
STEP 4 — deliberately request a 404 ...
Status code: 404

Your dates, byte counts, and the negotiated HTTP version (HTTP/2 or HTTP/1.1) will differ — see expected-output/FIELDS.md for exactly which parts are fixed and which vary, including the httpbin.org/httpbingo.org fallback note.

Validation steps

  1. Run bash examples/http_explorer.sh — it must reach Step 2 with Status code: 200.
  2. Confirm Step 3 shows "hello": "world" echoed back in the json field.
  3. Confirm Step 4 prints Status code: 404.
  4. Complete the four exercises in starter/http_explorer.sh and run it — it should print a 200, the echoed body, and a 404.
  5. Run the tests (next section) — all checks that run must pass.

Tests

bash tests/run_tests.sh

Expected final line online: 7 checks, 0 failure(s), 0 skip(s). Offline it reads 5 checks, 0 failure(s), 1 skip(s). — the network checks are skipped, not failed. The command exits 0 on success (including the offline path), so it is safe in CI.

Cleanup

Nothing to clean up: the scripts send read-only and harmless test requests and write nothing outside their own console output. To reset your edits, restore the starter files from git: git checkout -- starter/http_explorer.sh starter/http-worksheet.md.

Troubleshooting

See troubleshooting.md for the full list (curl missing, httpbin returning 503, -d and the method, redirects, and the offline path).

Security notes

See security.md. Short version: the lab talks only to public test endpoints, the {"hello":"world"} body is non-sensitive sample data, and you must never send a real API key or secret to a public echo service — a rule that carries straight into your model-API work.

Extension exercises

  1. Use the HEAD method — curl -I https://example.com — and note it returns the response headers with no body; it is GET without the download.
  2. Measure a round trip: curl -w "time_total: %{time_total}s\n" -o /dev/null -s https://example.com, and reason about what that time includes.
  3. Walk every status class with the test service: request /status/200, /status/301, /status/403, and /status/500 on https://httpbin.org (or the mirror), printing just the code, and map each to its class and to the "whose fault, what to do" rule.
  • Previous day: Day 17 — the lesson before this one in the computing-foundations section.
  • Next day: Day 19 — HTTPS and TLS: Encryption on the Wire (builds directly on today by encrypting the very messages you just sent).

Expected output

FIELDS.md

# What a correct run shows (all platforms)

`sample-run.txt` in this directory is a **real captured run** (macOS, curl
8.7.1, 2026-07-12). Your run will differ in the details below, but the shape
is fixed.

A correct run prints, in order:

1. `=== HTTP Explorer ===` and `Network reachable: yes` (or `no` when offline).
2. **Step 1** — the request lines (each starting `>`) and the response status
   line and headers (each starting `<`). The status line reads `HTTP/2 200` or
   `HTTP/1.1 200 OK` depending on which version curl and the server negotiate;
   both are correct. The dates, `age`, and `cf-ray` values change every run.
3. **Step 2** — `Status code: 200`.
4. **Step 3** — the JSON echo, whose key part is:

   ```text
     "json": {
       "hello": "world"
     }
   ```

5. **Step 4** — `Status code: 404`.
6. `=== End of HTTP Explorer ===`.

## About the echo service (httpbin.org vs the mirror)

The lesson and exercises use **`https://httpbin.org`** as the canonical free
test service. It is shared and unmetered, so it sometimes returns `503 Service
Temporarily Unavailable` or times out. When that happens the reference script
automatically falls back to **`https://httpbingo.org`**, the compatible mirror
of the same project, which returns the identical `"json"` echo shape. That is
why the captured `sample-run.txt` shows `Using echo service:
https://httpbingo.org` — httpbin.org was busy at capture time. When httpbin.org
is up, the `Host` in the POST/404 URLs reads `httpbin.org` instead; everything
else is the same.

## Offline behavior

With no network reachable, the script prints `Network reachable: no`, lists
what each step *would* show, and exits 0. No captured file is needed for that
path; it produces no live output by design.

sample-run.txt

=== HTTP Explorer ===
Network reachable: yes
------------------------------------------------------------
STEP 1 — curl -v https://example.com
(Request lines start with '>', response headers with '<'.)
> GET / HTTP/2
> Host: example.com
> User-Agent: curl/8.7.1
> Accept: */*
>
< HTTP/2 200
< date: Sun, 12 Jul 2026 08:37:20 GMT
< content-type: text/html
< server: cloudflare
< last-modified: Wed, 01 Jul 2026 17:50:18 GMT
< allow: GET, HEAD
< accept-ranges: bytes
< age: 1918
< cf-cache-status: HIT
< cf-ray: a19eb9b11de990f3-BOM
<
------------------------------------------------------------
STEP 2 — status code only for https://example.com
Status code: 200
------------------------------------------------------------
Using echo service: https://httpbingo.org
------------------------------------------------------------
STEP 3 — POST a JSON body to https://httpbingo.org/post
Request body sent: {"hello":"world"}
Server echoed the 'json' field back as:
  "json": {
    "hello": "world"
  }
------------------------------------------------------------
STEP 4 — deliberately request a 404 from https://httpbingo.org/status/404
Status code: 404  (4xx = client error: the resource was not found)
------------------------------------------------------------
=== End of HTTP Explorer ===

Source files

examples/http_explorer.sh (4364 bytes)
#!/usr/bin/env bash
# Day 018 lab — Speak HTTP by Hand (reference implementation).
#
# Sends real HTTP requests with curl against free public test services and
# reads the raw request/response. Degrades gracefully:
#   * OFFLINE  -> skips the live requests, explains what each WOULD show, exits 0.
#   * httpbin.org busy (it is a shared free service and sometimes returns 503)
#     -> automatically falls back to its compatible mirror httpbingo.org so the
#        POST-echo and 404 demos still work.
#
# Run from the lab directory:
#   bash examples/http_explorer.sh
set -u

GOOD_URL="https://example.com"          # reliable, only serves GET/HEAD
HTTPBIN="https://httpbin.org"           # canonical test service (per the lesson)
HTTPBIN_MIRROR="https://httpbingo.org"  # compatible mirror, same JSON echo shape

hr() { printf '%s\n' "------------------------------------------------------------"; }

# Return a base URL for the echo/status demos: prefer httpbin.org, fall back to
# its mirror. We verify with the ACTUAL POST echo (not just a GET probe),
# because these shared free services sometimes answer GET while the echo still
# fails under load. Returns "" if neither host echoes right now.
pick_echo_service() {
  local base body
  for base in "${HTTPBIN}" "${HTTPBIN_MIRROR}"; do
    body="$(curl -s -X POST -H "Content-Type: application/json" -d '{"hello":"world"}' --max-time 10 "${base}/post" 2>/dev/null)"
    if printf '%s' "${body}" | grep -q '"hello"'; then
      printf '%s' "${base}"
      return 0
    fi
  done
  printf '%s' ""
}

# Network gate: a quick, time-limited request to a rock-solid host.
online="no"
if curl -s -o /dev/null --max-time 8 "${GOOD_URL}"; then
  online="yes"
fi

echo "=== HTTP Explorer ==="
echo "Network reachable: ${online}"
hr

if [ "${online}" != "yes" ]; then
  echo "OFFLINE MODE — no network reachable, so the live requests are skipped."
  echo "When online, this script would show you:"
  echo "  1. curl -v ${GOOD_URL}"
  echo "     -> your request lines (>) and the response's 'HTTP/.. 200' status line (<)."
  echo "  2. curl -s -o /dev/null -w '%{http_code}' ${GOOD_URL}"
  echo "     -> the bare status code 200, with the body thrown away."
  echo "  3. curl -X POST -H 'Content-Type: application/json' -d '{\"hello\":\"world\"}' ${HTTPBIN}/post"
  echo "     -> a JSON body echoing your payload back in its \"json\" field."
  echo "  4. curl -s -o /dev/null -w '%{http_code}' ${HTTPBIN}/status/404"
  echo "     -> the status code 404, produced on purpose."
  echo "=== End (offline) ==="
  exit 0
fi

# 1. Verbose: see BOTH messages. Request lines start with '>', response with '<'.
echo "STEP 1 — curl -v ${GOOD_URL}"
echo "(Request lines start with '>', response headers with '<'.)"
# -s hides the progress meter; 2>&1 merges curl's verbose stream (stderr) so we
# can filter it. We show only the request/status/header lines, not the HTML body.
curl -s -v "${GOOD_URL}" -o /dev/null 2>&1 | grep -E '^[<>]' | head -n 16
hr

# 2. Read ONLY the status code. -o /dev/null discards the body; -w prints the code.
echo "STEP 2 — status code only for ${GOOD_URL}"
code="$(curl -s -o /dev/null -w '%{http_code}' "${GOOD_URL}")"
echo "Status code: ${code}"
hr

# Choose the echo/status service for steps 3 and 4.
ECHO_BASE="$(pick_echo_service)"
if [ -z "${ECHO_BASE}" ]; then
  echo "NOTE: both httpbin.org and its mirror are busy right now (a shared free"
  echo "service, so this happens). Steps 3-4 are skipped; rerun in a minute."
  echo "The GET checks above already succeeded, so your network and curl are fine."
  echo "=== End of HTTP Explorer ==="
  exit 0
fi
echo "Using echo service: ${ECHO_BASE}"
hr

# 3. POST a JSON body and watch the service echo it back.
echo "STEP 3 — POST a JSON body to ${ECHO_BASE}/post"
echo "Request body sent: {\"hello\":\"world\"}"
echo "Server echoed the 'json' field back as:"
curl -s -X POST -H "Content-Type: application/json" -d '{"hello":"world"}' "${ECHO_BASE}/post" \
  | grep -A2 '"json"'
hr

# 4. Trigger a 404 on purpose so a failing status becomes information, not alarm.
echo "STEP 4 — deliberately request a 404 from ${ECHO_BASE}/status/404"
code404="$(curl -s -o /dev/null -w '%{http_code}' "${ECHO_BASE}/status/404")"
echo "Status code: ${code404}  (4xx = client error: the resource was not found)"
hr

echo "=== End of HTTP Explorer ==="
metadata.yml (602 bytes)
lesson_id: D018
day: 18
kind: api-example
languages: [bash]
setup_commands:
  - cd labs/sections/computing-foundations/day-018-http-requests-responses-and-methods
run_commands:
  - bash examples/http_explorer.sh
  - bash starter/http_explorer.sh
test_commands:
  - bash tests/run_tests.sh
cleanup_commands:
  - 'git checkout -- starter/http_explorer.sh starter/http-worksheet.md  # optional: reset your work'
requires_network: true
requires_api_key: false
estimated_minutes: 30
last_executed: '2026-07-12'
executed_on: 'macOS (curl 8.7.1), bash tests/run_tests.sh -> 7 checks, 0 failure(s), 0 skip(s)'
requirements/README.md (900 bytes)
# Dependencies — Day 018 lab

**Just `curl`, which is already installed.** This lab has one tool dependency
and it ships with your OS:

- `curl` — the command-line HTTP client. Preinstalled on macOS and on every
  mainstream Linux distribution. Check with `curl --version`.
- `bash` ≥ 3.2 and the standard `grep` — also part of the base system.

If `curl` is somehow missing (rare, or a minimal container), install it with
the Day 13 package manager:

- macOS: `brew install curl`
- Debian/Ubuntu: `sudo apt install curl`
- Fedora: `sudo dnf install curl`

**Optional:** HTTPie (`http`) is the friendlier client shown in the lesson.
Install it with `brew install httpie` or `sudo apt install httpie` if you want
to try it — it is not required for any exercise or test.

There is no `requirements.txt`/`package.json`: the lab needs no language
runtime, only `curl` and a network connection.
starter/http_explorer.sh (3162 bytes)
#!/usr/bin/env bash
# Day 018 lab — Speak HTTP by Hand (YOUR working file).
#
# Complete the FOUR numbered exercises below by replacing each
#   : "EXERCISE n — ..."      (a no-op placeholder line)
# with the exact curl command named in its comment. The finished reference
# version is in examples/http_explorer.sh — run that first to see the goal.
#
# Run from the lab directory:
#   bash starter/http_explorer.sh
set -u

GOOD_URL="https://example.com"
HTTPBIN="https://httpbin.org"

echo "=== HTTP Explorer (starter) ==="

# A quick network gate so the script degrades gracefully offline.
if ! curl -s -o /dev/null --max-time 8 "${GOOD_URL}"; then
  echo "OFFLINE — no network reachable. Reconnect and rerun to do the exercises."
  echo "=== End (offline) ==="
  exit 0
fi
echo "Network reachable: yes"
echo "------------------------------------------------------------"

# ---------------------------------------------------------------------------
# EXERCISE 1 — See BOTH messages with the verbose flag.
#   Run:  curl -v https://example.com
#   Lines starting '>' are your request; lines starting '<' are the response,
#   beginning with the status line. (This prints the HTML body too — that's ok.)
echo "EXERCISE 1 — curl -v ${GOOD_URL}"
: "EXERCISE 1 — replace this line with: curl -v \"${GOOD_URL}\""
echo "------------------------------------------------------------"

# ---------------------------------------------------------------------------
# EXERCISE 2 — Read ONLY the status code.
#   Run:  curl -s -o /dev/null -w "%{http_code}\n" https://example.com
#   -s silences the meter, -o /dev/null throws the body away, -w prints the code.
#   You should see 200.
echo "EXERCISE 2 — status code only for ${GOOD_URL}"
: "EXERCISE 2 — replace this line with the curl -s -o /dev/null -w command above"
echo "------------------------------------------------------------"

# ---------------------------------------------------------------------------
# EXERCISE 3 — POST a JSON body and watch it echoed back.
#   Run:  curl -X POST -H "Content-Type: application/json" \
#              -d '{"hello":"world"}' https://httpbin.org/post
#   -X POST sets the method, -H adds a header, -d supplies the body (and makes
#   it a POST). Look for your data in the response's "json" field.
#   (If httpbin.org is busy and returns 503, retry, or use https://httpbingo.org/post.)
echo "EXERCISE 3 — POST a JSON body to ${HTTPBIN}/post"
: "EXERCISE 3 — replace this line with the curl -X POST ... command above"
echo "------------------------------------------------------------"

# ---------------------------------------------------------------------------
# EXERCISE 4 — Trigger a 404 on purpose.
#   Run:  curl -s -o /dev/null -w "%{http_code}\n" https://httpbin.org/status/404
#   The test service returns whatever status you ask for. You should see 404.
echo "EXERCISE 4 — deliberately request a 404 from ${HTTPBIN}/status/404"
: "EXERCISE 4 — replace this line with the curl -s -o /dev/null -w 404 command above"
echo "------------------------------------------------------------"

echo "=== End of HTTP Explorer (starter) ==="
starter/http-worksheet.md (2005 bytes)
# HTTP worksheet — Day 018

Fill this in by running `curl` yourself. Every answer comes from a command you
run in the terminal; copy the real values you see.

## 1. Status code of a normal GET

Command:

```bash
curl -s -o /dev/null -w "%{http_code}\n" https://example.com
```

- Status code returned: `__________`  (expected: a 2xx success)
- Which status class is that, and what does the class mean? `__________`

## 2. The Content-Type header of a page

Run the verbose request and find the `content-type` line in the **response**
headers (the lines starting with `<`):

```bash
curl -v https://example.com 2>&1 | grep -i "^< content-type"
```

- `Content-Type` reported: `__________`  (expected: `text/html`)
- In one sentence, what does `Content-Type` tell the client to do? `__________`

## 3. What httpbin.org/post echoes back for your POST body

Send a JSON body of your choosing (change the values if you like) and read the
`json` field of the response:

```bash
curl -s -X POST -H "Content-Type: application/json" \
     -d '{"hello":"world"}' https://httpbin.org/post
```

(If httpbin.org returns 503, retry once or use `https://httpbingo.org/post`.)

- The body you sent: `__________`
- What the `"json"` field of the response contained: `__________`
- Did the `headers` section of the response show the `Content-Type` you sent?
  `__________`

## 4. Short answer: 401 vs 429

In 4–6 sentences, explain why a `401` and a `429` require **completely
different** responses from your code. Name whose fault each is (client or
server), and say what you should do for each — for example, why retrying a
`401` unchanged can never succeed, while a `429` calls for slowing down.

```
____________________________________________________________________________
____________________________________________________________________________
____________________________________________________________________________
____________________________________________________________________________
```
tests/run_tests.sh (3118 bytes)
#!/usr/bin/env bash
# Tests for the Day 018 lab. Run from the lab directory:
#   bash tests/run_tests.sh
#
# Structure checks always run. Network checks (a real 200 from a known-good URL
# and a real POST-body echo) run only when the network is reachable; offline
# they are SKIPPED with a clear message. The script exits 0 unless a check that
# actually ran failed.
set -u

lab_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
failures=0
checks=0
skips=0

GOOD_URL="https://example.com"
HTTPBIN="https://httpbin.org"
HTTPBIN_MIRROR="https://httpbingo.org"

check() {
  local label="$1" ok="$2"
  checks=$((checks + 1))
  if [ "${ok}" = "yes" ]; then
    echo "  ok: ${label}"
  else
    echo "  FAIL: ${label}"
    failures=$((failures + 1))
  fi
}

skip() {
  skips=$((skips + 1))
  echo "  skip: $1"
}

echo "Structure checks ..."
# The three scripts/worksheet the learner needs must exist and be non-trivial.
for f in "examples/http_explorer.sh" "starter/http_explorer.sh" "starter/http-worksheet.md"; do
  if [ -s "${lab_dir}/${f}" ]; then check "${f} exists and is non-empty" "yes"; else check "${f} exists and is non-empty" "no"; fi
done
# The example script must reference curl and the good URL.
if grep -q "curl" "${lab_dir}/examples/http_explorer.sh"; then check "example uses curl" "yes"; else check "example uses curl" "no"; fi
if grep -q "example.com" "${lab_dir}/examples/http_explorer.sh"; then check "example references the known-good URL" "yes"; else check "example references the known-good URL" "no"; fi

echo
echo "Network checks ..."
# Is the network up? Probe the rock-solid host with a short timeout.
if curl -s -o /dev/null --max-time 8 "${GOOD_URL}"; then
  # Check 1: a known-good URL returns 200.
  code="$(curl -s -o /dev/null -w '%{http_code}' --max-time 15 "${GOOD_URL}")"
  if [ "${code}" = "200" ]; then check "GET ${GOOD_URL} returns 200" "yes"; else check "GET ${GOOD_URL} returns 200 (got ${code})" "no"; fi

  # Check 2: a POST body is echoed back. Try the ACTUAL POST against httpbin.org
  # first, then its mirror — a GET probe can succeed while the echo still fails,
  # because these shared free services flap under load. Pass on the first host
  # that genuinely echoes the body. If NEITHER echoes, SKIP (a third-party
  # outage is not the learner's fault) rather than fail the suite.
  echoed="no"
  echoed_by=""
  for base in "${HTTPBIN}" "${HTTPBIN_MIRROR}"; do
    body="$(curl -s -X POST -H "Content-Type: application/json" -d '{"hello":"world"}' --max-time 15 "${base}/post" 2>/dev/null)"
    if printf '%s' "${body}" | grep -q '"hello"' && printf '%s' "${body}" | grep -q '"world"'; then
      echoed="yes"; echoed_by="${base}"; break
    fi
  done

  if [ "${echoed}" = "yes" ]; then
    check "POST body is echoed back by ${echoed_by}" "yes"
  else
    skip "POST echo — httpbin.org and its mirror are both busy right now; rerun later (network and GET are fine)"
  fi
else
  skip "network unreachable — 200 and POST-echo checks skipped (offline is fine)"
fi

echo
echo "${checks} checks, ${failures} failure(s), ${skips} skip(s)."
[ "${failures}" -eq 0 ]

Troubleshooting

Troubleshooting — Day 018 lab

curl: command not found

Rare on macOS and Linux, where curl is preinstalled. Install it with your Day 13 package manager: brew install curl (macOS) or sudo apt install curl (Debian/Ubuntu). Confirm with curl --version.

httpbin.org returns 503 Service Temporarily Unavailable (or times out)

httpbin.org is a free, shared, unmetered service, so it occasionally rate- limits or is briefly overloaded — this is expected, not a mistake on your part. Options:

  • Retry in a minute; outages are usually short.
  • Use the mirror https://httpbingo.org, which is a compatible copy of the same project and returns the identical "json" echo shape. Just swap the host: https://httpbingo.org/post, https://httpbingo.org/status/404.

The reference script (examples/http_explorer.sh) and the tests already fall back to the mirror automatically, and the tests skip (never fail) the echo check if both services are down — a third-party outage is not your fault.

My POST behaves like a GET / the body isn't there

You dropped the -d flag or its value. -d '{"hello":"world"}' does two things: it supplies the request body and switches the method to POST. Add -v and read the request line (> POST /post ...) to confirm the method.

The status-code command prints nothing (or glues the number to my prompt)

You likely left out -o /dev/null (so the body scrolled past the code) or the trailing \n in -w "%{http_code}\n" (so the number has no newline after it). Use the full form: curl -s -o /dev/null -w "%{http_code}\n" https://example.com.

I see 301 or 302 instead of 200

You requested an http:// URL that redirects to https:// (or a path that moved). Add -L to make curl follow redirects, or request the https:// URL directly. This is the 3xx redirection class doing its job.

The status line says HTTP/2 but the lesson shows HTTP/1.1

Both are correct. curl and the server negotiate the newest version they both support; a modern server behind a CDN answers HTTP/2 (or HTTP/3). The methods, headers, and status codes are identical across versions — only the wire format differs.

curl -v floods my screen with HTML

-v also prints the response body (the page's HTML). To see only the request/response lines, pipe through a filter and discard the body: curl -s -v https://example.com -o /dev/null 2>&1 | grep -E '^[<>]'.

No internet / offline

Both scripts detect this: they print Network reachable: no, describe what each step would show, and exit 0. The tests skip the network checks with a clear message. Reconnect and rerun to do the live exercises.

Windows: bash is not recognized

Use WSL (wsl --install, then open Ubuntu and follow the Linux path). Native PowerShell has a curl alias that maps to Invoke-WebRequest with different flags, so the commands here will not work as written outside WSL.

Security notes

Security notes — Day 018 lab

  • What the scripts do: send a handful of small HTTP requests with curl to public test endpoints onlyhttps://example.com (a reserved example domain) and https://httpbin.org / https://httpbingo.org (free request- echo test services). They write no files, change no settings, and need no elevated privileges.

  • The POST body is non-sensitive sample data. The only data this lab sends is {"hello":"world"} (or values you choose). An echo service like httpbin.org reflects your entire request back — body and headers — and logs traffic. That is fine for a throwaway sample, and it is exactly why the next rule matters.

  • Never send real secrets to a public echo service. Do not put a real API key, password, token, or personal data in an Authorization header, a -d body, or a query string aimed at httpbin.org or any test endpoint — you would be handing your credential to a third party and its logs. When you start calling real model APIs, the token goes only to that provider's own https:// endpoint, never to a test service.

  • Plain HTTP is not private. This lab uses https:// throughout. Anything sent over plain http:// travels in readable text that anyone on the path can see — the reason tomorrow's lesson (HTTPS and TLS) exists. Make https:// your default from today.

  • Read scripts before running them. Both scripts here are short and commented; read them first. Running unread shell scripts that make network calls is a common way to get compromised — a habit this course reinforces.