Baeldung Pro – Linux – NPI EA (cat = Baeldung on Linux)
announcement - icon

Learn through the super-clean Baeldung Pro experience:

>> Membership and Baeldung Pro.

No ads, dark-mode and 6 months free of IntelliJ Idea Ultimate to start with.

1. Introduction

curl is a powerful command-line tool for transferring data using various protocols, such as HTTP. It is widely used for sending data via HTTP methods such as POST or PUT. When sending data with curl via HTTP requests, it’s common to have line breaks within the content.

However, when attempting to insert line breaks (newlines) within the data payload, common escape sequences like \n may not function as expected. These may be interpreted literally rather than as newline characters.

In this tutorial, we’ll walk through different ways to send line breaks using curl effectively, with practical code examples.

2. Setting up an HTTP Server

The primary challenge is ensuring that the data sent by curl includes properly formatted line breaks, especially when interacting with APIs or web services that require specific formatting.

To test the proposed solutions, we’ll set up a Python server to receive the curl POST requests.

Therefore, let’s use the script post_server.py to spin up a basic Python server and examine how it handles line breaks:

$ cat post_server.py
from http.server import BaseHTTPRequestHandler, HTTPServer
class MyRequestHandler(BaseHTTPRequestHandler):
    def do_POST(self):
        # Get content length
        content_length = int(self.headers['Content-Length'])
        # Read the POST data
        post_data = self.rfile.read(content_length).decode('utf-8')
        # Log the received data
        print("Received POST data:")
        print(post_data)
        # Respond to the client
        self.send_response(200)
        self.send_header('Content-type', 'text/html')
        self.end_headers()
        self.wfile.write(b"POST request received!")
def run(server_class=HTTPServer, handler_class=MyRequestHandler, port=8000):
    server_address = ('', port)
    httpd = server_class(server_address, handler_class)
    print(f'Server running on port {port}...')
    httpd.serve_forever()
if __name__ == '__main__':
    run()

The Python code above creates a basic HTTP server, listens on a specified port, processes POST requests, and reads the incoming data. Subsequently, the server prints the received data in the terminal and responds to the client with a message confirming that it received the request.

We can now start up the Python server in the terminal:

$ python3 post_server.py 
Server running on port 8000...

Now that we’ve started the server, we can test the different solutions for handling line breaks.

3. Using –data-binary and ANSI-C Quoting for Verbatim Data

The –data-binary option instructs the curl command to send the data exactly as provided. Additionally, we add ANSI-C quoting ($’..’) to the strings we send inside the curl command. Notably, the –data-binary option prevents curl from altering the content of the data.

This is particularly important when we need precise formatting, such as when we send multiline text, files, or specific content types such as multipart/form-data.

In a separate terminal, let’s illustrate the use of –data-binary and ANSI-C quoting within a simple curl command:

$ curl -v -X POST --data-binary $'Hello\nWorld' http://localhost:8000/hello
...
> POST /hello HTTP/1.1
> Host: localhost:8000
> User-Agent: curl/8.5.0
> Accept: */*
> Content-Length: 12
> Content-Type: application/x-www-form-urlencoded
> 
* HTTP 1.0, assume close after body
< HTTP/1.0 200 OK
< Server: BaseHTTP/0.6 Python/3.12.3
< Date: Sun, 29 Sep 2024 21:45:27 GMT
< Content-type: text/html
< 
* Closing connection

In this example, we’ve sent Hello and World as two separate lines to the destination server.

The result shows that the data was sent properly via the curl POST request. To confirm the format of the sent data, we can check the server terminal and read its output:

$ python3 post_server.py 
Server running on port 8000...
Received POST data:
Hello
World
127.0.0.1 - - [29/Sep/2024 23:28:03] "POST /hello HTTP/1.1" 200 -

The output confirms that the data was sent in the correct format and that the line break was interpreted accurately.

4. Using ANSI-C Quoting

Although it’s safer when used with the –data-binary option, curl can send newline characters using the ANSI-C quoting method alone. This allows escape sequences like \n to be interpreted correctly.

The method provides precise control over escape sequences and is efficient for short strings that we can write directly in the command line without involving external files.

Now, let’s see how we can use this method within the curl command:

$ curl -X POST -d $'my message\nwith a newline' http://localhost:8000/hello
POST request received!

Here’s the terminal output on the Python server side, showing how the data was received:

$ python3 post_server.py 
Server running on port 8000...
Received POST data:
my message
with a newline
127.0.0.1 - - [30/Sep/2024 00:36:58] "POST /hello HTTP/1.1" 200 -

The server printed out the message in two lines, which demonstrates that the server correctly interpreted the line break.

5. Sending Multiline Files

Sometimes, we store the data we want to send in a file that contains newlines. The –data-binary option of curl enables us to upload the file without altering its content.

For illustration, we’ll use file.txt, which contains data with multiple newlines:

$ cat file.txt
Hello
World
This is a multiline file.

Next, we’ll make a POST request to upload the content of file.txt to the Python server side, where we’ll examine the data format:

$ curl -X POST --data-binary @/home/gbenga/file.txt http://localhost:8000/hello
POST request received!

As shown above, curl sent the POST request successfully. The –data-binary option instructed the curl command not to alter the content of file.txt. We added the @ symbol to the file path, prompting curl to read the content of the file and include it as part of the request.

Now, let’s take a look at the format of the data sent on the Python server side:

$ python3 post_server.py 
Server running on port 8000...
Received POST data:
Hello
World
This is a multiline file.

The Python server interpreted the multiline breaks correctly. In this case, curl sent the content of file.txt exactly as it appears, including all line breaks.

6. Using Inline Data With Standard Input

In scenarios where users prefer embedding data directly within the command, curl supports reading from standard input using @-. Consequently, this method is useful when sending multiline data without relying on external files.

Let’s illustrate this method with a simple example:

$ curl -X POST --data-binary @- http://localhost:8000/hello <<EOF
This is line one
This is line two
EOF
POST request received!

As shown above, the here-document syntax enables specifying multiple lines of text directly within the terminal. Subsequently, let’s switch to the Python server terminal and see the data output:

$ python3 post_server.py 
Server running on port 8000...
Received POST data:
This is line one
This is line two

This indicates that the server has successfully received the data sent in the request. Furthermore, the server interprets the data within the body of the request correctly.

7. Conclusion

In this article, we explored how to use the curl command to handle line breaks effectively. This is essential for many use cases, such as sending formatted text, log data, or file contents. So, understanding these methods allows for precise control over the data sent via HTTP requests.

By applying these techniques, we can easily complete tasks involving multiline data transfers with curl.