diff --git a/config.sh.template b/config.sh.template
index d0e5e54..066154d 100755
--- a/config.sh.template
+++ b/config.sh.template
@@ -11,4 +11,5 @@ SERVER="" # server hostname, optionally with subdirectories
STATUS="draft" # one of publish,future,draft,pending,private
CATEGORIES="" # comma separated integer IDs of categories
TAGS="" # comma separated integer IDs of tags
+# USER_AGENT="Mozilla/5.0 (X11; Linux x86_64) wordpress-rest-curl/1.0" # uncomment to override; some hosts' DDoS/bot protection blocks curl's default UA
diff --git a/post.sh b/post.sh
index b6b7744..aafb5af 100755
--- a/post.sh
+++ b/post.sh
@@ -11,6 +11,7 @@ STATUS="draft" # one of publish,future,draft,pending,private
CATEGORIES="" # comma separated integer IDs of categories
TAGS="" # comma separated integer IDs of tags
TMPFILE=/tmp/wordpress-post.txt # location of a temporary file with the post text
+USER_AGENT="Mozilla/5.0 (X11; Linux x86_64) wordpress-rest-curl/1.0" # some hosts block curl's default UA as bot traffic
CONFIG_DIR="${WORDPRESS_REST_CURL_CONFIG_DIR:-$HOME/.config/wordpress-rest-curl}"
# CLI options:
@@ -129,12 +130,14 @@ PAYLOAD=$(jq -n \
BASE_URL="$SERVER"
[[ "$BASE_URL" != http://* && "$BASE_URL" != https://* ]] && BASE_URL="https://$BASE_URL"
+BASE_URL="${BASE_URL%/}"
URL="$BASE_URL/wp-json/wp/v2/posts/"
[[ -n "$POST_ID" ]] && URL="$BASE_URL/wp-json/wp/v2/posts/$POST_ID"
# push the post!
RESPONSE=$(curl --silent --show-error --user "$USER:$PASSWORD" -X POST \
-H "Content-Type: application/json" \
+ -A "$USER_AGENT" \
--data "$PAYLOAD" \
-w '\n%{http_code}' \
"$URL")
diff --git a/tests/mock_wp_server.py b/tests/mock_wp_server.py
index 9940fa6..652656c 100755
--- a/tests/mock_wp_server.py
+++ b/tests/mock_wp_server.py
@@ -7,7 +7,8 @@
# determines the response to the next request. If absent, responds
# 201 with the submitted fields echoed back under an "id".
# MOCK_WP_REQUEST_FILE - overwritten on every request with
-# {"path": ..., "payload": ...} so a test can assert on what was sent.
+# {"path": ..., "payload": ..., "user_agent": ...} so a test can assert
+# on what was sent.
#
# Listens on 127.0.0.1:$MOCK_WP_PORT (default 8899).
@@ -30,7 +31,11 @@ class Handler(http.server.BaseHTTPRequestHandler):
data = {"_raw": body.decode(errors="replace")}
with open(REQUEST_FILE, "w") as f:
- json.dump({"path": self.path, "payload": data}, f)
+ json.dump({
+ "path": self.path,
+ "payload": data,
+ "user_agent": self.headers.get("User-Agent", ""),
+ }, f)
status, resp_body = 201, {"id": 1, **data}
if os.path.exists(CONTROL_FILE):
diff --git a/tests/run_tests.sh b/tests/run_tests.sh
index 824b52e..df569e7 100755
--- a/tests/run_tests.sh
+++ b/tests/run_tests.sh
@@ -75,6 +75,27 @@ assert_eq "create: status" "publish" "$(jq -r '.payload.status' <<<"$REQ")"
assert_eq "create: categories sent as array" "[3,7]" "$(jq -c '.payload.categories' <<<"$REQ")"
assert_eq "create: tags sent as array" "[10]" "$(jq -c '.payload.tags' <<<"$REQ")"
assert_eq "create: content rendered as markdown" "true" "$(jq -r '.payload.content | test("markdown")' <<<"$REQ")"
+assert_eq "create: sends a non-default user agent" "true" "$(jq -r '.user_agent != "" and (.user_agent | test("^curl/") | not)' <<<"$REQ")"
+
+# --- USER_AGENT is configurable, e.g. to dodge a host's DDoS protection ---
+rm -f "$MOCK_WP_REQUEST_FILE" "$MOCK_WP_CONTROL_FILE"
+cat >> "$HOME/.config/wordpress-rest-curl/config.sh" <<'EOF3'
+USER_AGENT="Mozilla/5.0 (test override)"
+EOF3
+run_post_sh --file "$POST_FILE" >/dev/null
+assert_eq "user agent: exit code" "0" "$?"
+REQ=$(cat "$MOCK_WP_REQUEST_FILE")
+assert_eq "user agent: override from config is sent" "Mozilla/5.0 (test override)" "$(jq -r '.user_agent' <<<"$REQ")"
+
+# --- trailing slash on SERVER doesn't produce a double slash in the URL ---
+rm -f "$MOCK_WP_REQUEST_FILE" "$MOCK_WP_CONTROL_FILE"
+cat >> "$HOME/.config/wordpress-rest-curl/config.sh" </dev/null
+assert_eq "trailing slash: exit code" "0" "$?"
+REQ=$(cat "$MOCK_WP_REQUEST_FILE")
+assert_eq "trailing slash: path has no double slash" "/wp-json/wp/v2/posts/" "$(jq -r '.path' <<<"$REQ")"
# --- edit an existing post ---
rm -f "$MOCK_WP_REQUEST_FILE" "$MOCK_WP_CONTROL_FILE"