みんなの「教えて(疑問・質問)」にみんなで「答える」Q&Aコミュニティ

こんにちはゲストさん。会員登録(無料)して質問・回答してみよう!

解決済みの質問

C言語ソケットでWikipediaの情報入手

以下のCコードで
> gcc wiki_client.c -o wiki_client
> ./wiki_client "O'Reilly_Media"
として
https://en.wikipedia.org/wiki/O%27Reilly_Media
の情報を得ようとしているのですが、
HTTP/1.1 400 Bad Request
が返ってきます。
これは本に載っていたままのコードなのですが、
どこをどう直せばいいのか分かりません。
どこを直せばいいか教えて下さい。

ブラウザからはもちろんアクセスできます。
環境はUbuntu 18.04のgcc 7.3.0です。
ではよろしくお願いします。

// wiki_client.c
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <netdb.h>

void error(char *msg)
{
fprintf(stderr, "%s: %s\n", msg, strerror(errno));
exit(1);
}

int open_socket(char *host, char *port)
{
struct addrinfo *res;
struct addrinfo hints;
memset(&hints, 0, sizeof(hints));
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
if (getaddrinfo(host, port, &hints, &res) == -1)
error("Can't resolve the address");
int d_sock = socket(res->ai_family, res->ai_socktype,
res->ai_protocol);
if (d_sock == -1)
error("Can't open socket");
int c = connect(d_sock, res->ai_addr, res->ai_addrlen);
freeaddrinfo(res);
if (c == -1)
error("Can't connect to socket");
return d_sock;
}

int say(int socket, char *s)
{
int result = send(socket, s, strlen(s), 0);
if (result == -1)
fprintf(stderr, "%s: %s\n", "Error talking to the server",
strerror(errno));
return result;
}

int main(int argc, char *argv[])
{
int d_sock;
d_sock = open_socket("en.wikipedia.org", "80");
char buf[255];
sprintf(buf, "GET /wiki/%s http/1.1\r\n", argv[1]);
say(d_sock, buf);
say(d_sock, "Host: en.wikipedia.org\r\n\r\n");
char rec[256];
int bytesRcvd = recv(d_sock, rec, 255, 0);
while (bytesRcvd) {
if (bytesRcvd == -1)
error("Can't read from server");
rec[bytesRcvd] = '\0';
printf("%s", rec);
bytesRcvd = recv(d_sock, rec, 255, 0);
}
close(d_sock);
return 0;
}

投稿日時 - 2019-03-11 14:37:36

QNo.9595857

困ってます

質問者が選んだベストアンサー

"400 Bad Request"と返ってきてしまう原因は、プログラムの下記の部分にあります。
sprintf(buf, "GET /wiki/%s http/1.1\r\n", argv[1]);
小文字ではなく大文字でHTTP/1.1と書いてください。

ただし、そこを直しても意図した結果を得ることはできません。その本は古いのでしょう。Wikipediaは今ではhttp:ではなくてhttps:を使うように変わってしまったためです。
http://en.wikipedia.org/wiki/Aにアクセスしようとすると
https://en.wikipedia.org/wiki/Aへのリダイレクトが発生し、HTTPステータスコード301が返ってくることはそのプログラムで確認することができると思います。
しかし、そのプログラムではhttps:での通信に対応できないのです。

投稿日時 - 2019-03-11 18:48:08

お礼

ベストアンサーを差し上げます。

なるほど、最初の関門は大文字・小文字だったんですね。本の記載が小文字でした。直すと確かにhttps:へのリダイレクトが発生して301が返ってきました:

> ./wiki_client "O'Reilly_Media"
HTTP/1.1 301 TLS Redirect
Date: Mon, 11 Mar 2019 12:48:57 GMT
Server: Varnish
X-Varnish: 714716381
X-Cache: cp5007 int
X-Cache-Status: int-front
Server-Timing: cache;desc="int-front"
Set-Cookie: WMF-Last-Access=11-Mar-2019;Path=/;HttpOnly;secure;Expires=Fri, 12 Apr 2019 12:00:00 GMT
Set-Cookie: WMF-Last-Access-Global=11-Mar-2019;Path=/;Domain=.wikipedia.org;HttpOnly;secure;Expires=Fri, 12 Apr 2019 12:00:00 GMT
X-Client-IP: 126.15.51.117
Location: https://en.wikipedia.org/wiki/O'Reilly_Media
Content-Length: 0
Connection: keep-alive

読み込みは完了できてはいませんが、満足です。今、この本で出来る限りのことはしました。今度、別の本でhttps:での通信について勉強しようと思います。
丁寧に教えて下さって、ありがとうございました!

投稿日時 - 2019-03-11 21:59:01

ANo.1

このQ&Aは役に立ちましたか?

0人が「このQ&Aが役に立った」と投票しています

回答(1)

あなたにオススメの質問