简体   繁体   English

如何在不使用libcurl的情况下从本地服务器获取URL

[英]How to get the URL from a localhost server without using libcurl

I've made a custom HTTP server that serves an HTML page with some text, an input text box for entering a command, and a submit button. 我已经制作了一个自定义HTTP服务器,该服务器为HTML页面提供一些文本,用于输入命令的输入文本框和一个提交按钮。 Upon receiving a form submission, the server is supposed to run the given command and serve a response containing the results. 收到表单提交后,服务器应运行给定命令并提供包含结果的响应。

The issue I cant quite figure out is how to get the URLs of form submission requests so as to parse out the command to run. 我无法弄清楚的问题是如何获取表单提交请求的URL,以解析出要运行的命令。 As presently implemented, the server runs on localhost:3838, and when the client browses to that URL the server responds correctly with the form. 按照目前的实现,服务器在localhost:3838上运行,并且当客户端浏览到该URL时,服务器将使用该表单正确响应。 When the user enters (say) the command ls in the text box and clicks the "run" submission button, a request is issued to localhost:3838/run?command=ls . 当用户在文本框中输入(说)命令ls并单击“运行”提交按钮时,将向localhost:3838/run?command=ls发出请求。 How can I obtain that URL in the server, so as to parse out and execute the command? 如何在服务器中获取该URL,以便解析并执行命令?

Here's the present server code: 这是当前的服务器代码:

CwebServer.c CwebServer.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <signal.h>

#define PORT "3838" //port being connected to 
#define MAXLEN 800
#define BACKLOG 10 //number of pending connections to be held in queue

//format of html page 

char header []= 
"HTTP/1.1 200 Ok\r\n"
"Content-Type: text/html; charset=UTF-8\r\n\r\n"
"<!DOCTYPE html>\r\n"
"<html>\n"
"<head>\n"
"<title>Web-Based Remote Command Server</title>\r\n"
"</head>\n"
"<body>\n\n";
char input []=
"<form action= \"/run\" method= \"GET\"> \n"
"Command: <input type=\"text\" size=\"100\" name=\"command\">\n"
"<input type=\"submit\" value=\"Run\">\n"
"</form>";
char output []=
"<p>Command that was run and testing this:</p>\n"
"<pre>Your server will include the command that was just run here.</pre>\n\n"
"<p>Standard Output:</p>\n""<pre>Your server will include the stdout results here.</pre>\n\n"
"<p>Standard Error:</p>\n"
"<pre>Your server will include the stderr results here.</pre>\r\n\r\n"
"</body>\r\n""</html>\r\n";

char *buff = header; 

void sigchld_handler(int s)
{
    (void)s; // quiet unused variable warning

    // waitpid() might overwrite errno, so we save and restore it:
    int saved_errno = errno;

    while(waitpid(-1, NULL, WNOHANG) > 0);

    errno = saved_errno;
}


void *get_in_addr(struct sockaddr *sa)
{
    if (sa->sa_family == AF_INET) {
        return &(((struct sockaddr_in*)sa)->sin_addr);
    }

    return &(((struct sockaddr_in6*)sa)->sin6_addr);
}


int main (void){
    int sockfd;
    int new_fd; 
    struct addrinfo hints;
    struct addrinfo *serverinfo; 
    struct addrinfo *p;
    struct sockaddr_storage client_addr;
    socklen_t addrsize;
    struct sigaction sa;
    int yes = 1;
    char s[INET6_ADDRSTRLEN];
    int status;

    memset(&hints, 0, sizeof hints); //makes struct empty 
    hints.ai_family = AF_UNSPEC; //IPv4 or v6 
    hints.ai_socktype = SOCK_STREAM; //TCP type need 
    hints.ai_flags = AI_PASSIVE; //Fill in IP for us 


    //if can't get address info print error 
    if((status = getaddrinfo(NULL, PORT, &hints, &serverinfo)) != 0){
        fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(status));
        return 1;
    }


    for(p = serverinfo; p != NULL; p = p->ai_next){
        if((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1){
            perror("server: socket");
            continue;
        }

        if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1){
            perror("setsockopt");
            exit(1);
        }

        if(bind(sockfd, p->ai_addr, p->ai_addrlen) == -1){
            close(sockfd);
            perror("server: bind");
            continue;
        }

        break;
    }

    freeaddrinfo(serverinfo);

    if(p == NULL){
        fprintf(stderr, "server: failed to bind\n");
        exit(1);
    }

    if(listen(sockfd, BACKLOG) == -1){
        perror("listen");
        exit(1);
    }

    sa.sa_handler = sigchld_handler; // reap all dead processes
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = SA_RESTART;
    if (sigaction(SIGCHLD, &sa, NULL) == -1) {
        perror("sigaction");
        exit(1);
    }

    printf("server: waiting for connections....\n");

    while(1){
        addrsize = sizeof client_addr;
        new_fd = accept(sockfd, (struct sockaddr *)&client_addr, &addrsize);
        if(new_fd == -1){
            perror("Did not accept");
            continue;
        }

        inet_ntop(client_addr.ss_family, get_in_addr((struct sockaddr *)&client_addr), s, sizeof s);
        printf("server: got connection from %s\n", s);

        if(!fork()){
            close(sockfd);
            int bufsize = 1024;
            char *buffer = malloc(bufsize);
            send(new_fd, header, bufsize, 0);
            //write(new_fd, "HTTP/1.1 200 OK\n", 16);
            //write(new_fd, "Content-length: 46\n", 19);
            //write(new_fd, "Content-type: text/html\n\n", 25);
            //write(new_fd, "<html><head>\n<head>\n<title>The CAvengers Web Page</title>\n</head>\n</html>", 46);

            if(send(new_fd, buffer, MAXLEN, 0) == -1)
                perror("send");
            close(new_fd);
            exit(0);
        }
        close(new_fd);
    }

    return 0;


}

Web servers and clients communicate via the HTTP protocol. Web服务器和客户端通过HTTP协议进行通信。 That's what makes them web servers as opposed to some other kind. 这就是使它们成为Web服务器而不是其他类型服务器的原因。 HTTP is a request / response protocol: the client sends a request to the server that contains information about what it's requesting , and the server processes that request to determine how to respond. HTTP是一种请求/响应协议:客户端向服务器发送一个请求,该请求包含有关其请求的信息 ,服务器处理该请求以确定如何响应。

Your particular server seems to intend to implement HTTP 1.1 . 您的特定服务器似乎打算实现HTTP 1.1 This is not the most recent version of the protocol, but that's ok. 这不是该协议的最新版本,但是可以。 Pretty much every HTTP client in the world understands that dialect. 世界上几乎每个HTTP客户端都了解该方言。 But yours is a pretty minimally-functioning server, responding to every established connection with the same HTTP response, even if the client does not actually send an HTTP request. 但是您的服务器是一个功能最差的服务器,即使客户端实际上没有发送HTTP请求,它也会使用相同的HTTP响应来响应每个已建立的连接。

Your question is how to get the request URI. 您的问题是如何获取请求URI。 The answer is to read it from the client, via the connected socket returned by accept() . 答案是通过accept()返回的连接套接字从客户端读取它。 The read() or recv() function would be appropos for that. read()recv()函数将是适合的。 The format you should expect the client to use is described in the HTTP specifications I linked above, but in very brief, you should expect the request to start with the request method name ( GET ), at least one space, the request URI, and a carriage-return / linefeed pair. 我上面链接的HTTP规范中描述了您期望客户端使用的格式,但是简单,您应该期望请求以请求方法名称( GET ),至少一个空格,请求URI和回车符/换行符对。 You will need to parse the request URI to distinguish between an initial request for the form and a form submission, and in the latter case you will be able to parse the query parameters as well. 您将需要解析请求URI,以区分表单的初始请求和表单提交,在后一种情况下,您还可以解析查询参数。

DO NOTE, however, that although HTTP is a comparatively simple protocol, it is still much more complicated than I've just described. 请注意,尽管HTTP是一个相对简单的协议,但它仍然比我刚刚描述的要复杂得多。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM