Computing Foundations › How the Internet Works › Day 18
Hands-on lab — Day 18: HTTP: Requests, Responses, and Methods
- ← Back to the Day 18 lesson
- Open the hands-on files on GitHub — clone or download them from the public labs repository
- Local path in your clone:
labs/sections/computing-foundations/day-018-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
- Lesson title: HTTP: Requests, Responses, and Methods
- Day number: 18 of 365
- Lesson article: https://ai-roadmap-365.github.io/day-018-http-requests-responses-and-methods
- Lab files: everything you need is in this directory — follow “How to run” below.
- Browse the course locally: from the repository root, this lab also appears in the course website at
/labs/day-018-http-requests-responses-and-methodswhen the site is running.
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
curland 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
POSTwith a JSON body and confirm the server received it by reading the echo. - Trigger a
404on purpose and classify it (4xx= your request was wrong). - Explain, for a
401versus a429, 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
curlandbash). - Windows — use WSL (Windows Subsystem for Linux) and follow the Linux path;
curlalso 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) runscurl -v https://example.comand shows the request/response lines, (Step 2) prints just the200status code, (Step 3)POSTs{"hello":"world"}and shows the server echoing it back in itsjsonfield, and (Step 4) requests a404on purpose and prints the code. Ifhttpbin.orgis busy it falls back to the compatible mirrorhttpbingo.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 fourcurlcommands 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 real200fromexample.comand a realPOSTecho) 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
- Run
bash examples/http_explorer.sh— it must reachStep 2withStatus code: 200. - Confirm Step 3 shows
"hello": "world"echoed back in thejsonfield. - Confirm Step 4 prints
Status code: 404. - Complete the four exercises in
starter/http_explorer.shand run it — it should print a200, the echoed body, and a404. - 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
- Use the
HEADmethod —curl -I https://example.com— and note it returns the response headers with no body; it isGETwithout the download. - 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. - Walk every status class with the test service: request
/status/200,/status/301,/status/403, and/status/500onhttps://httpbin.org(or the mirror), printing just the code, and map each to its class and to the "whose fault, what to do" rule.
Navigation
- 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
curlto public test endpoints only —https://example.com(a reserved example domain) andhttps://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 likehttpbin.orgreflects 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
Authorizationheader, a-dbody, or a query string aimed athttpbin.orgor 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 ownhttps://endpoint, never to a test service. -
Plain HTTP is not private. This lab uses
https://throughout. Anything sent over plainhttp://travels in readable text that anyone on the path can see — the reason tomorrow's lesson (HTTPS and TLS) exists. Makehttps://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.