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.