Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
unix
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Analytics
Analytics
Repository
Value Stream
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Commits
Open sidebar
tu-wien
unix
Commits
2f552e5a
Commit
2f552e5a
authored
Nov 05, 2018
by
Ivaylo Ivanov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add working http client
parent
69612815
Changes
3
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
142 additions
and
10 deletions
+142
-10
.gitignore
.gitignore
+4
-0
http/Makefile
http/Makefile
+3
-3
http/client.c
http/client.c
+135
-7
No files found.
.gitignore
View file @
2f552e5a
.vscode/
.vscode/
*.out
*.out
*.o
*.o
*.html
!public/*.html
http/client
http/server
http/Makefile
View file @
2f552e5a
...
@@ -21,7 +21,7 @@ install:
...
@@ -21,7 +21,7 @@ install:
cp
$(TARGET_2)
/usr/local/bin/myhttp-
$(TARGET_2)
cp
$(TARGET_2)
/usr/local/bin/myhttp-
$(TARGET_2)
clean
:
clean
:
$(RM)
$(TARGET_1)
.o
$(RM)
$(TARGET_1)
$(RM)
$(TARGET_1)
$(RM)
$(TARGET_2)
.o
$(RM)
$(TARGET_2)
$(RM)
$(TARGET_2)
$(RM)
*
.o
$(RM)
*
.html
\ No newline at end of file
http/client.c
View file @
2f552e5a
...
@@ -28,6 +28,8 @@
...
@@ -28,6 +28,8 @@
#include "shared/http.h"
#include "shared/http.h"
static
struct
addrinfo
*
get_host_info
(
const
char
*
hostname
,
char
*
port
);
static
struct
addrinfo
*
get_host_info
(
const
char
*
hostname
,
char
*
port
);
static
int
create_socket
(
struct
addrinfo
*
config
);
static
void
process_response
(
char
reply
[
sizeof
(
int32_t
)],
char
*
ofile
,
char
*
dir
);
int
main
(
int
argc
,
char
*
argv
[])
{
int
main
(
int
argc
,
char
*
argv
[])
{
check_opts_number
(
argc
);
check_opts_number
(
argc
);
...
@@ -79,13 +81,41 @@ int main(int argc, char *argv[]) {
...
@@ -79,13 +81,41 @@ int main(int argc, char *argv[]) {
url
=
argv
[
optind
];
url
=
argv
[
optind
];
}
}
const
char
*
full_url
=
strstr
(
url
,
"http://"
)
+
7
;
//< the full url starts after http://
char
*
base_url
=
strstr
(
url
,
"http://"
)
+
7
;
//< the base url starts after http://
const
char
*
path
=
strstr
(
full_url
,
"/"
);
const
char
*
hostname
=
"google.com"
;
//< TODO: Change this later
struct
addrinfo
*
res
=
get_host_info
(
hostname
,
port
);
//< Check if the address is resolvable
const
char
*
path
=
strstr
(
base_url
,
"/"
);
if
(
path
==
NULL
)
path
=
"/"
;
//< Set the root path if there is none
freeaddrinfo
(
res
);
//< Free the addrinfo struct
const
char
*
hostname
=
strtok
(
base_url
,
";/?:@=&"
);
//< Get the FQDN of the remote
struct
addrinfo
*
config
=
get_host_info
(
hostname
,
port
);
//< Check if the address is resolvable
char
header
[
strlen
(
base_url
)
+
100
];
//< Create a variable to store the header
snprintf
(
header
,
sizeof
header
,
"GET %s HTTP/1.1
\r\n
Host: %s
\r\n
Connection: close
\r\n\r\n
"
,
path
,
hostname
);
//< Build the header
int
sockfd
=
create_socket
(
config
);
if
(
connect
(
sockfd
,
config
->
ai_addr
,
config
->
ai_addrlen
)
==
-
1
)
{
//< Connect to the host
(
void
)
fprintf
(
stderr
,
"ERROR: Failure connecting to the server.
\n
"
);
exit
(
EXIT_FAILURE
);
}
if
((
send
(
sockfd
,
header
,
strlen
(
header
),
0
))
<
0
)
{
//< Send the GET request
(
void
)
fprintf
(
stderr
,
"ERROR: Failure sending the request to the server.
\n
"
);
exit
(
EXIT_FAILURE
);
}
char
reply
[
sizeof
(
int32_t
)];
//< Set the variable to hold the server response. Set to a big length
if
((
recv
(
sockfd
,
reply
,
strlen
(
reply
)
-
1
,
0
))
<
0
)
{
//< Receive response from the remote (-1 for the trailing terminating char)
(
void
)
fprintf
(
stderr
,
"ERROR: Did not receive response from the remote.
\n
"
);
exit
(
EXIT_FAILURE
);
}
process_response
(
reply
,
ofile
,
dir
);
freeaddrinfo
(
config
);
//< Free the addrinfo struct
}
}
static
void
print_usage
(
void
)
{
static
void
print_usage
(
void
)
{
...
@@ -115,7 +145,7 @@ static void check_opts_number(int argc) {
...
@@ -115,7 +145,7 @@ static void check_opts_number(int argc) {
/**
/**
* @brief Function to check if the address is resolvable by the client
* @brief Function to check if the address is resolvable by the client
* @details Checks if the address is resolvable by the client.
* @details Checks if the address is resolvable by the client.
* If the address is resolvable, it
writes the result to res
* If the address is resolvable, it
returns the result
* If the address is not resolvable, it exits with an error
* If the address is not resolvable, it exits with an error
* @param
* @param
* hostname - The address to be resolved
* hostname - The address to be resolved
...
@@ -138,7 +168,6 @@ static struct addrinfo* get_host_info(const char *hostname, char *port) {
...
@@ -138,7 +168,6 @@ static struct addrinfo* get_host_info(const char *hostname, char *port) {
(
void
)
fprintf
(
stderr
,
"ERROR: %s
\n
"
,
gai_strerror
(
err
));
(
void
)
fprintf
(
stderr
,
"ERROR: %s
\n
"
,
gai_strerror
(
err
));
exit
(
EXIT_FAILURE
);
//< Exit if there is an error
exit
(
EXIT_FAILURE
);
//< Exit if there is an error
}
}
if
(
res
==
NULL
)
{
if
(
res
==
NULL
)
{
(
void
)
fprintf
(
stderr
,
"ERROR: Could not resolve address %s
\n
"
,
hostname
);
(
void
)
fprintf
(
stderr
,
"ERROR: Could not resolve address %s
\n
"
,
hostname
);
exit
(
EXIT_FAILURE
);
//< Exit if the address is not resolved
exit
(
EXIT_FAILURE
);
//< Exit if the address is not resolved
...
@@ -146,3 +175,102 @@ static struct addrinfo* get_host_info(const char *hostname, char *port) {
...
@@ -146,3 +175,102 @@ static struct addrinfo* get_host_info(const char *hostname, char *port) {
return
res
;
return
res
;
}
}
/**
* @brief Function to create a socker using the supplied configuration
* @details Creates a socket using the supplied configuration
* If there was no error, it returns the socket
* If there was an error, it exits and displays an error message
* @param config - The the configuration to be used for the socket creation
* @return sockfd - The socket obtained from the socket creation
**/
static
int
create_socket
(
struct
addrinfo
*
config
)
{
int
sockfd
=
socket
(
config
->
ai_family
,
config
->
ai_socktype
,
config
->
ai_protocol
);
if
(
sockfd
<
0
)
{
(
void
)
fprintf
(
stderr
,
"ERROR: Socket creation failed.
\n
"
);
exit
(
EXIT_FAILURE
);
}
return
sockfd
;
}
/**
* @brief Function to process the response of the remote host
* @details Processes the reply according to its' content and the ofile and dir parameters
* The function checks the response code does the following:
* - if the reponse code is invalid, it exits with an error
* - if the response code is different from 200, it prints the whole response and exits with status 3
* - if the response code is 200, it prints it to the console or saves it as a file
* If there was an error, it exits and displays an error message
* @param config - The the configuration to be used for the socket creation
* @return null
**/
static
void
process_response
(
char
reply
[
sizeof
(
int32_t
)],
char
*
ofile
,
char
*
dir
)
{
char
*
http_version
=
"HTTP/1.1"
;
if
(
strncmp
(
reply
,
http_version
,
strlen
(
http_version
))
==
0
)
{
//< Check if the remote gives a correct response header
char
cresponse_code
[
3
];
//< Array for the response code. Response codes are always 3 digits long
strncpy
(
cresponse_code
,
strstr
(
reply
,
"HTTP/1.1 "
)
+
sizeof
(
http_version
)
+
1
,
3
);
//< Get the response code as string.
int
response_code
=
strtol
(
cresponse_code
,
NULL
,
10
);
//< Get the response code as integer
if
(
response_code
==
0
)
{
fprintf
(
stderr
,
"ERROR: Protocol error.
\n
"
);
exit
(
EXIT_FAILURE
);
}
else
if
(
response_code
!=
200
)
{
printf
(
"%s
\n
"
,
strtok
(
reply
,
"
\r\n
"
));
//< Get the first line
exit
(
EXIT_SUCCESS
);
}
char
*
body
=
strstr
(
reply
,
"
\r\n\r\n
"
)
+
4
;
if
(
ofile
==
NULL
&&
dir
==
NULL
)
printf
(
"%s"
,
body
);
//< Print the body of the response
else
{
if
(
ofile
!=
NULL
)
{
FILE
*
out
=
NULL
;
out
=
fopen
(
ofile
,
"w"
);
if
(
out
==
NULL
)
{
(
void
)
fprintf
(
stderr
,
"ERROR: Could not open ./%s for writing."
,
ofile
);
exit
(
EXIT_FAILURE
);
}
else
{
fprintf
(
out
,
"%s"
,
body
);
fclose
(
out
);
printf
(
"File ./%s successfully written.
\n
"
,
ofile
);
exit
(
EXIT_SUCCESS
);
}
}
else
if
(
dir
!=
NULL
)
{
FILE
*
out
=
NULL
;
char
path
[
sizeof
(
dir
)
+
100
];
if
(
dir
[
strlen
(
dir
)
-
1
]
==
'/'
)
snprintf
(
path
,
sizeof
path
,
"%sresult.html"
,
dir
);
else
snprintf
(
path
,
sizeof
path
,
"%s/result.html"
,
dir
);
out
=
fopen
(
path
,
"w"
);
//< Open <path>/result.html for writing
if
(
out
==
NULL
)
{
if
(
dir
[
strlen
(
dir
)
-
1
]
==
'/'
)
(
void
)
fprintf
(
stderr
,
"ERROR: Could not open %sresult.html for writing.
\n
"
,
dir
);
else
(
void
)
fprintf
(
stderr
,
"ERROR: Could not open %s/result.html for writing.
\n
"
,
dir
);
exit
(
EXIT_FAILURE
);
}
else
{
fprintf
(
out
,
"%s"
,
body
);
fclose
(
out
);
if
(
dir
[
strlen
(
dir
)
-
1
]
==
'/'
)
printf
(
"File %sresult.html successfully written.
\n
"
,
dir
);
else
printf
(
"File %s/result.html successfully written.
\n
"
,
dir
);
exit
(
EXIT_SUCCESS
);
}
}
}
}
else
{
fprintf
(
stderr
,
"ERROR: Protocol error.
\n
"
);
exit
(
EXIT_FAILURE
);
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment