Home > Net >  not terminating scanf() or gets() after taking newline
not terminating scanf() or gets() after taking newline

Time:06-16

I have to take three inputs in a single string.
The code to take the input is:

char msg_send[1000];
gets(msg_send);

The input is like

GET /api HTTP/1.1  

id=1&name=phoenix&[email protected]

That means there is a newline after the fist line GET /api HTTP/1.1. The next line is an empty newline. The input taking function should terminate after taking the 3rd newline.

Also, I have to terminate the input after the first line GET /something HTTP/1.1 if the line doesn't have a /api word at the place of /something word.

But when I'm using gets(), it terminates the string after taking GET /api HTTP/1.1 part of the input. When using scanf, it terminates after taking only the first GET word. Is there any way to take the input as a single string?

CodePudding user response:

Reading from the FILE * should be done with fgets(), not gets() which cannot be used safely. Testing for the proper URL should be strict: strstr(msg_send, "/api") is not sufficient: GET /something/api will match. Comparing the request to GET /api HTTP/1.1 or possibly omitting the /1.1 seems safer.

Here is a modified version:

// read the HTTP request, return the number of lines
int get_http_request(FILE *fp, char *buf, size_t size) {
    char line2[100];
    char line3[4096];

    *buf = '\0';
    if (!fgets(buf, size, fp))
        return 0;  // fp at end of file

    if (strncmp(buf, "GET /api HTTP/", 14))
        return 1;  // not the proper protocol or URL

    size_len = strlen(buf);
    if (!fgets(buf   len, size - len, fp))
        return 1;  // missing blank line

    size_len  = strlen(buf   len);
    if (!fgets(buf   len, size - len, fp))
        return 2;  // missing contents

    return 3;  // 3 lines were read
}

CodePudding user response:

In cases like these, you should just use getchar in a loop:

#define MAX_MSG_BUF 1000

char char msg_send[MAX_MSG_BUF];    

// you should wrap the below code in a function, like get3lines(buf, buf_size)
unsigned index = 0;
unsigned line_count = 0; 
const unsigned buf_size = MAX_MSG_BUF;
do {
    int tmp = getchar();
    if (tmp < 0) break; // end of file or error
    msg_send[index  ] = tmp;
    if (tmp == '\n') {
          line_count;
        if (line_count == 1) {
            // check that first line contains /api                
            if (!first_line_valid(msg_send, index)) break;
        }
    }
} while (index < (MAX_MSG_BUF-1) && line_count < 3;
msg_send[index] = '\0';
// print error if line_count < 3 ?

The first_line_valid function might look like this (note: needs #include <stdbool.h> for bool type):

bool starts_with(const char *str, size_t length, const char *prefix) {
    size_t i = 0;
    for(;;) {            
        if (i == length || prefix[i] == '\0') return true;
        if (str[i] != prefix[i]) return false; // does catch end of str
          i;
     }
}

bool first_line_valid(const char *buf, size_t buf_size) {
    // note: buf might not be NUL-terminated so use buf_size
    if (starts_with(buf, buf_size, "GET /api ")) return true;
    if (starts_with(buf, buf_size, "GET /api/")) return true;
    return false;
}

CodePudding user response:

So, I figured out the answer. The answer is I should use a condition if there is /api in the command. The code is like:

char msg_send[1000], blank[4], data[300];
fgets(msg_send, 1000, stdin);
        char *header = strstr(msg_send, "/api");

        if (header)
        {
            fgets(blank, 4, stdin);
            fgets(data, 300, stdin);
            strcat(msg_send, " ");
            strcat(msg_send, data);
        }

I should take the first part as a string and then judge if it has the word /api. If it doesn't contain, the input taking should end. Thanks to everyone for your useful opinions.

  • Related