Skip to content

Commit

Permalink
BUG/MINOR: detect when a raw configuration is uploaded incorrectly
Browse files Browse the repository at this point in the history
Return an error when the user tries to upload an HAProxy configuration
file without any newline character. This can happen for example when
using curl(1) with bad options:

  # BAD! This will url-encode the file.
  curl -H 'Content-Type: text/plain' -d @haproxy.cfg $URL

  # GOOD. Upload without encoding.
  curl -H 'Content-Type: text/plain' -T haproxy.cfg $URL

Note that we still allow to upload an empty configuration, since this
is supported by HAProxy in master-worker mode, and it may actually be
useful in future releases.
  • Loading branch information
oliwer committed May 5, 2023
1 parent 4c14425 commit a412d0f
Show file tree
Hide file tree
Showing 6 changed files with 139 additions and 0 deletions.
34 changes: 34 additions & 0 deletions e2e/tests/raw/data/haproxy.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
global
chroot /var/lib/haproxy
user haproxy
group haproxy
maxconn 4000
pidfile /var/run/haproxy.pid
stats socket /var/lib/haproxy/stats level admin
log 127.0.0.1 local2

defaults
mode http
maxconn 3000
log global
option httplog
option redispatch
option dontlognull
option http-server-close
option forwardfor except 127.0.0.0/8
timeout http-request 10s
timeout check 10s
timeout connect 10s
timeout client 1m
timeout queue 1m
timeout server 1m
timeout http-keep-alive 10s
retries 3

backend test_backend
mode http
balance roundrobin
option forwardfor
server server_01 10.1.1.1:8080 check weight 80
server server_02 10.1.1.2:8080 check weight 80
server server_03 10.1.1.2:8080 check weight 80
1 change: 1 addition & 0 deletions e2e/tests/raw/data/haproxy.cfg.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"global\n chroot /var/lib/haproxy\n user haproxy\n group haproxy\n maxconn 4000\n pidfile /var/run/haproxy.pid\n stats socket /var/lib/haproxy/stats level admin\n log 127.0.0.1 local2\n\ndefaults\n mode http\n maxconn 3000\n log global\n option httplog\n option redispatch\n option dontlognull\n option http-server-close\n option forwardfor except 127.0.0.0/8\n timeout http-request 10s\n timeout check 10s\n timeout connect 10s\n timeout client 1m\n timeout queue 1m\n timeout server 1m\n timeout http-keep-alive 10s\n retries 3\n\nbackend test_backend\n mode http\n balance roundrobin\n option forwardfor\n server server_01 10.1.1.1:8080 check weight 80\n server server_02 10.1.1.2:8080 check weight 80\n server server_03 10.1.1.2:8080 check weight 80\n"
30 changes: 30 additions & 0 deletions e2e/tests/raw/get.bats
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#!/usr/bin/env bats
#
# Copyright 2023 HAProxy Technologies
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http:#www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

load '../../libs/dataplaneapi'
load "../../libs/get_json_path"
load '../../libs/haproxy_config_setup'
load '../../libs/resource_client'

load 'utils/_helpers'

@test "raw: Download configuration" {
resource_get "$_RAW_BASE_PATH"
assert_equal "$SC" 200
test -n "$(get_json_path "$BODY" .data)" ||
fail "failed to download raw config. BODY: '$BODY'"
}
36 changes: 36 additions & 0 deletions e2e/tests/raw/post.bats
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#!/usr/bin/env bats
#
# Copyright 2023 HAProxy Technologies
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http:#www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

load '../../libs/dataplaneapi'
load '../../libs/debug'
load "../../libs/get_json_path"
load '../../libs/haproxy_config_setup'
load '../../libs/resource_client'
load '../../libs/version'

load 'utils/_helpers'

@test "raw: Post new configuration" {
resource_post "$_RAW_BASE_PATH" 'data/haproxy.cfg.json'
assert_equal "$SC" 202
}

@test "raw: Post new configuration incorrectly (bug 1219)" {
resource_post_text "$_RAW_BASE_PATH" 'data/haproxy.cfg.json'
assert_equal "$SC" 400
assert_equal "$(get_json_path "$BODY" '.message')" "invalid configuration: no newline character found"
}
29 changes: 29 additions & 0 deletions e2e/tests/raw/utils/_helpers.bash
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#!/usr/bin/env bash
#
# Copyright 2023 HAProxy Technologies
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http:#www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

_RAW_BASE_PATH="/services/haproxy/configuration/raw"

# Identical to resource_post() but with the text/plain content type.
function resource_post_text() {
local endpoint="$1" data="@${BATS_TEST_DIRNAME}/$2" qs_params="$3"

run curl -m 10 -s -H 'content-type: text/plain' --user dataplaneapi:mypassword \
"-XPOST" -w "\n%{http_code}" "-d${data}" \
"http://${LOCAL_IP_ADDRESS}:${E2E_PORT}${BASE_PATH}${endpoint}?$qs_params&version=$(version)"
assert_success
dpa_curl_status_body '$output'
}
9 changes: 9 additions & 0 deletions handlers/raw.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,15 @@ func (h *PostRawConfigurationHandlerImpl) Handle(params configuration.PostHAProx
onlyValidate = *params.OnlyValidate
}

// Check for a common error where the user ran `curl -d @haproxy.cfg` without
// converting the file to json, which removes all the \n from the configuration.
if len(params.Data) > 0 && !strings.ContainsRune(params.Data, '\n') {
code := misc.ErrHTTPBadRequest
msg := "invalid configuration: no newline character found"
e := &models.Error{Code: &code, Message: &msg}
return configuration.NewPostHAProxyConfigurationBadRequest().WithPayload(e)
}

cfg, err := h.Client.Configuration()
if err != nil {
e := misc.HandleError(err)
Expand Down

0 comments on commit a412d0f

Please sign in to comment.