-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathclient_main.c
203 lines (147 loc) · 4.85 KB
/
client_main.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
#include "client_main.h"
/*
Parse arguments with getopt(), and return whether is -G or -P. Next, malloc and set URL to optarg value.
Caution! you have to free *URL when program is closed.
*/
int parseArguments(int argc, char *argv[], char **URL)
{
int c = 0;
while((c = getopt(argc, argv, "g:p:")) != -1)
{
if(c == '?') // 인식 오류나면
{
if(optopt == 'g' || optopt == 'p')
printf("client needs URL\n");
return ERR;
}
else // 인식 오류 안나면
{
//*URL = (char*)malloc(strlen(optarg) + 1); // optarg로 들어온 url을 넣어준다.
*URL = copyString(optarg);
//memcpy(*URL, optarg, strlen(optarg) + 1);
if(c == 'g') return GET;
else if(c == 'p') return POST;
}
}
return ERR;
}
struct URL* parseURL(char *url_string)
{
struct URL *url = (struct URL*)malloc(sizeof(struct URL));
/*char *pure_url = str_alloc(strlen(url_string) - 7); // http://를 제외한 순수한 url, http://를 제외해야하므로 7칸을 뺀만큼 할당한다. +1은 \0
strncpy(pure_url, url_string + 7, strlen(url_string) - 7);*/
char *pure_url = copyString(url_string);
char *port_start = index(pure_url, ':') + 1; // port 번호가 시작하는 문자열의 포인터
char *path_start = index(pure_url, '/'); // 포트 번호가 끝나는 문자열 포인터 + 1
int port_length = path_start - port_start; // 포트 길이를 계산
if(path_start == NULL)
{
path_start = pure_url + strlen(pure_url);
}
// 포트 파싱
char *port = str_alloc(port_length);
substr(port, port_start, path_start);
// path 파싱
char *path = str_alloc(strlen(path_start));
substr(path, path_start, pure_url + strlen(pure_url));
// ip 파싱
char *ip = str_alloc(port_start - 1 - pure_url);
substr(ip, pure_url, port_start - 1);
url->ip = ip;
url->port = port;
url->path = path;
free(pure_url);
return url;
}
char* readBody(int *length)
{
int n = 0;
int len = 0;
char *buf = str_alloc(BUF_SIZE);
char *content = str_alloc(BUF_SIZE);
content[0] = '\0';
while((n = fread(buf, 1, BUF_SIZE, stdin)) > 0) // 주의: strlen이 아닌 n값을 사용해야 한다.
{
len += n;
content = (char*)realloc(content, len);
if(content == NULL)
{
printf("realloc error\n");
exit(-1);
}
memcpy(content + len - n, buf, n);
memset(buf, 0, BUF_SIZE);
}
*length = len;
free(buf);
return content;
}
int httpRequest(struct HttpRequestMessage *message)
{
int sock = socket(PF_INET, SOCK_STREAM, 0);
if(sock < 0) return -1;
struct sockaddr_in server_addr; // sockaddr는 IP, port가 한 변수 안에 들어있어 사용하기 불편하므로 sockaddr_in 사용
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = inet_addr(message->ip);
server_addr.sin_port = htons(atoi(message->port));
int conn = connect(sock, (struct sockaddr*)&server_addr, sizeof(server_addr));
if(conn < 0)
{
printf("connect issue\n");
return -2;
}
char *msgString = makeRequestHeaderString(message);
write(sock, msgString, strlen(msgString));
int sendFileLength = 0;
int remain = message->contentLength;
int j;
if(message->method == POST)
{
int cursor = 0;
while(cursor < message->contentLength)
{
int writeLength = BUF_SIZE < remain ? BUF_SIZE : remain;
write(sock, message->body + cursor, writeLength);
cursor += BUF_SIZE;
remain -= writeLength;
sendFileLength += writeLength;
}
}
free(msgString);
int recvSize = 0;
char *buf = str_alloc(BUF_SIZE);
int count = 0;
while((recvSize = read(sock, buf, BUF_SIZE)) > 0)
{
if(buf != NULL)
{
write(1, buf, recvSize);
memset(buf, 0, BUF_SIZE);
count++;
}
}
free(buf);
close(sock);
}
int main(int argc, char *argv[])
{
char *url_string;
int method = parseArguments(argc, argv, &url_string); // GET or POST
struct URL *url = parseURL(url_string); // struct URL에 파싱한 url을 넣어줍니다.
char *body = NULL;
int contentLength = 0;
if(method == POST)
{
body = readBody(&contentLength);
}
char *version = makeString("1.0");
struct HttpRequestMessage *message = createRequestMessage(method, url, version, body, contentLength);
httpRequest(message);
freeRequestMessage(message);
freeURL(url);
free(url_string);
free(version);
free(body); // buf는 freeRequestMessage에서 해제해주지 않는다.
return 0;
}