kinda successful merge, weird tho, didn't go as smoothly with VScode as usual...
This commit is contained in:
9
memo.txt
9
memo.txt
@@ -1,5 +1,12 @@
|
|||||||
|
|
||||||
|
- do correct handling of special character in url (/rfc2119_files/errata.js.t%C3%A9l%C3%A9chargement -> /rfc2119_files/errata.js.téléchargement)
|
||||||
|
- handle redirection
|
||||||
|
- maybe add a "last_action_time" in Client for timeout handling
|
||||||
|
little global timeout on epoll, like 100ms, then find client that actualy need to timeout
|
||||||
|
if (actual_time - client.last_action_time > 10000ms){timeout(client)}
|
||||||
|
- add headers "Date" and "Last-Modified" to response
|
||||||
|
- change "std::string" to reference "std::string &" in most functions
|
||||||
|
and add "const" if apropriate.
|
||||||
- http_method en mode binary flags. "std::vector<http_method> allow_methods" -> "unsigned int allow_methods;"
|
- http_method en mode binary flags. "std::vector<http_method> allow_methods" -> "unsigned int allow_methods;"
|
||||||
- Dans le parsing, trier les "locations" par ordre de precision.
|
- Dans le parsing, trier les "locations" par ordre de precision.
|
||||||
Compter les "/" dans le chemin, les locations avec le plus de "/" seront en premier dans le vector.
|
Compter les "/" dans le chemin, les locations avec le plus de "/" seront en premier dans le vector.
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
|
|
||||||
#include "Client.hpp"
|
#include "Client.hpp"
|
||||||
|
|
||||||
|
char Client::buf[MAX_FILESIZE+1];
|
||||||
|
|
||||||
/*********************************************
|
/*********************************************
|
||||||
* COPLIENS
|
* COPLIENS
|
||||||
*********************************************/
|
*********************************************/
|
||||||
@@ -35,7 +37,7 @@ void Client::parse_request()
|
|||||||
std::vector<std::string> list;
|
std::vector<std::string> list;
|
||||||
size_t pos;
|
size_t pos;
|
||||||
|
|
||||||
pos = (raw_request).find("\r\n\r\n");
|
pos = (raw_request).find(CRLF CRLF);
|
||||||
sub = (raw_request).substr(0, pos);
|
sub = (raw_request).substr(0, pos);
|
||||||
list = split(sub, '\n');
|
list = split(sub, '\n');
|
||||||
// request_line
|
// request_line
|
||||||
@@ -45,9 +47,27 @@ void Client::parse_request()
|
|||||||
_parse_request_headers(list);
|
_parse_request_headers(list);
|
||||||
//body- message
|
//body- message
|
||||||
_parse_request_body(pos + 4);
|
_parse_request_body(pos + 4);
|
||||||
|
|
||||||
|
// add "raw_request.clear()" after parsing ? for little less memory usage ?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Client::clear()
|
||||||
|
{
|
||||||
|
clear_request();
|
||||||
|
raw_request.clear();
|
||||||
|
response.clear();
|
||||||
|
body_size = 0;
|
||||||
|
status = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Client::clear_request()
|
||||||
|
{
|
||||||
|
_request.method = UNKNOWN;
|
||||||
|
_request.path.clear();
|
||||||
|
_request.version.clear();
|
||||||
|
_request.headers.clear();
|
||||||
|
_request.body.clear();
|
||||||
|
}
|
||||||
|
|
||||||
http_method Client::get_method() { return _request.method; }
|
http_method Client::get_method() { return _request.method; }
|
||||||
std::string &Client::get_path() { return _request.path; }
|
std::string &Client::get_path() { return _request.path; }
|
||||||
|
|||||||
@@ -10,13 +10,14 @@
|
|||||||
|
|
||||||
struct Request
|
struct Request
|
||||||
{
|
{
|
||||||
std::map<std::string, std::string> headers;
|
|
||||||
http_method method;
|
http_method method;
|
||||||
std::string path;
|
std::string path;
|
||||||
std::string version;
|
std::string version;
|
||||||
|
std::map<std::string, std::string> headers;
|
||||||
std::string body;
|
std::string body;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# define MAX_FILESIZE 1000000 // (1Mo)
|
||||||
class Client
|
class Client
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -28,6 +29,8 @@ class Client
|
|||||||
int fd;
|
int fd;
|
||||||
std::string raw_request;
|
std::string raw_request;
|
||||||
std::string response;
|
std::string response;
|
||||||
|
static char buf[MAX_FILESIZE+1];
|
||||||
|
size_t body_size;
|
||||||
unsigned int status;
|
unsigned int status;
|
||||||
|
|
||||||
// const functions ?
|
// const functions ?
|
||||||
@@ -38,6 +41,8 @@ class Client
|
|||||||
std::string &get_headers(const std::string &key);
|
std::string &get_headers(const std::string &key);
|
||||||
|
|
||||||
void parse_request();
|
void parse_request();
|
||||||
|
void clear();
|
||||||
|
void clear_request();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct Request _request;
|
struct Request _request;
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ public:
|
|||||||
// there can only be one.
|
// there can only be one.
|
||||||
std::string root;
|
std::string root;
|
||||||
|
|
||||||
int client_body_limit; // set to default max if none set
|
unsigned int client_body_limit; // set to default max if none set
|
||||||
|
|
||||||
// might be the only one we let slide if bad input... It remains false...
|
// might be the only one we let slide if bad input... It remains false...
|
||||||
bool autoindex;
|
bool autoindex;
|
||||||
|
|||||||
@@ -124,5 +124,18 @@ int path_is_valid(std::string path)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void replace_all_substr(std::string &str, const std::string &ori_substr, const std::string &new_substr)
|
||||||
|
{
|
||||||
|
if (ori_substr.empty())
|
||||||
|
return;
|
||||||
|
size_t pos = 0;
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
pos = str.find(ori_substr, pos);
|
||||||
|
if (pos == std::string::npos)
|
||||||
|
break;
|
||||||
|
str.replace(pos, ori_substr.size(), new_substr);
|
||||||
|
pos += new_substr.size();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,9 +8,9 @@
|
|||||||
# include <cstdlib> // atoi
|
# include <cstdlib> // atoi
|
||||||
# include <sys/stat.h> // stat()
|
# include <sys/stat.h> // stat()
|
||||||
|
|
||||||
# include <iostream> // tmp
|
# define CR "\r"
|
||||||
|
# define LF "\n"
|
||||||
|
# define CRLF CR LF
|
||||||
|
|
||||||
// enum http_method
|
// enum http_method
|
||||||
// {
|
// {
|
||||||
@@ -38,5 +38,6 @@ std::string trim(std::string str, char c);
|
|||||||
http_method str_to_http_method(std::string &str);
|
http_method str_to_http_method(std::string &str);
|
||||||
std::string http_methods_to_str(unsigned int methods);
|
std::string http_methods_to_str(unsigned int methods);
|
||||||
int path_is_valid(std::string path);
|
int path_is_valid(std::string path);
|
||||||
|
void replace_all_substr(std::string &str, const std::string &ori_substr, const std::string &new_substr)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -28,6 +28,7 @@
|
|||||||
# include "Client.hpp"
|
# include "Client.hpp"
|
||||||
# include "ServerConfig.hpp"
|
# include "ServerConfig.hpp"
|
||||||
# include "utils.hpp"
|
# include "utils.hpp"
|
||||||
|
# include "http_status.hpp"
|
||||||
|
|
||||||
extern bool g_run;
|
extern bool g_run;
|
||||||
extern int g_last_signal;
|
extern int g_last_signal;
|
||||||
@@ -60,6 +61,8 @@ class Webserv
|
|||||||
std::vector<int> _listen_sockets;
|
std::vector<int> _listen_sockets;
|
||||||
std::vector<ServerConfig> _servers;
|
std::vector<ServerConfig> _servers;
|
||||||
std::vector<Client> _clients;
|
std::vector<Client> _clients;
|
||||||
|
std::map<int, std::string> _http_status;
|
||||||
|
std::map<std::string, std::string> _mime_types;
|
||||||
|
|
||||||
// accept.cpp
|
// accept.cpp
|
||||||
void _accept_connection(int fd);
|
void _accept_connection(int fd);
|
||||||
@@ -69,11 +72,23 @@ class Webserv
|
|||||||
// response.cpp
|
// response.cpp
|
||||||
void _response(Client *client);
|
void _response(Client *client);
|
||||||
void _send_response(Client *client, ServerConfig &server);
|
void _send_response(Client *client, ServerConfig &server);
|
||||||
|
|
||||||
|
void _append_base_headers(Client *client);
|
||||||
void _construct_response(Client *client, ServerConfig &server);
|
void _construct_response(Client *client, ServerConfig &server);
|
||||||
void _insert_status_line(Client *client, ServerConfig &server);
|
void _process_method(Client *client, ServerConfig &server, LocationConfig &location);
|
||||||
void _get_ressource(Client *client, ServerConfig &server, LocationConfig &location);
|
void _insert_status_line(Client *client);
|
||||||
|
void _error_html_response(Client *client, ServerConfig &server);
|
||||||
|
void _append_body(Client *client, const char *body, size_t body_size, const std::string &file_extension = "");
|
||||||
|
|
||||||
|
void _get(Client *client, ServerConfig &server, LocationConfig &location);
|
||||||
|
void _get_file(Client *client, const std::string &path);
|
||||||
|
|
||||||
void _post(Client *client, ServerConfig &server, LocationConfig &location);
|
void _post(Client *client, ServerConfig &server, LocationConfig &location);
|
||||||
|
void _post_file(Client *client, const std::string &path);
|
||||||
|
|
||||||
void _delete(Client *client, ServerConfig &server, LocationConfig &location);
|
void _delete(Client *client, ServerConfig &server, LocationConfig &location);
|
||||||
|
void _delete_file(Client *client, const std::string &path);
|
||||||
|
|
||||||
ServerConfig &_determine_process_server(Client *client);
|
ServerConfig &_determine_process_server(Client *client);
|
||||||
LocationConfig &_determine_location(ServerConfig &server, std::string &path);
|
LocationConfig &_determine_location(ServerConfig &server, std::string &path);
|
||||||
// cgi_script.cpp
|
// cgi_script.cpp
|
||||||
@@ -94,6 +109,8 @@ class Webserv
|
|||||||
// init.cpp
|
// init.cpp
|
||||||
void _bind(int socket_fd, in_port_t port, std::string host);
|
void _bind(int socket_fd, in_port_t port, std::string host);
|
||||||
void _listen(int socket_fd, unsigned int max_connections);
|
void _listen(int socket_fd, unsigned int max_connections);
|
||||||
|
void _init_http_status_map();
|
||||||
|
void _init_mime_types_map();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -12,6 +12,9 @@ Webserv::Webserv()
|
|||||||
throw std::runtime_error("Epoll init");
|
throw std::runtime_error("Epoll init");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_init_http_status_map();
|
||||||
|
_init_mime_types_map();
|
||||||
|
|
||||||
std::signal(SIGPIPE, signal_handler);
|
std::signal(SIGPIPE, signal_handler);
|
||||||
std::signal(SIGINT, signal_handler);
|
std::signal(SIGINT, signal_handler);
|
||||||
}
|
}
|
||||||
|
|||||||
41
srcs/webserv/http_status.hpp
Normal file
41
srcs/webserv/http_status.hpp
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
|
||||||
|
#ifndef HTTP_STATUS_HPP
|
||||||
|
# define HTTP_STATUS_HPP
|
||||||
|
|
||||||
|
// https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
|
||||||
|
|
||||||
|
/*
|
||||||
|
First version of macro HTML_ERROR(STATUS) dont work with call like this :
|
||||||
|
client->response.append( HTML_ERROR( _http_status[client->status].c_str() ) );
|
||||||
|
so I made the other version with dynamic replacement of STATUS .
|
||||||
|
*/
|
||||||
|
// # define HTML_ERROR(STATUS) "\r\n<!DOCTYPE html><html><head><title>"STATUS"</title></head><body><h1 style=\"text-align:center\">"STATUS"</h1><hr><p style=\"text-align:center\">Le Webserv/0.1</p></body></html>"
|
||||||
|
|
||||||
|
# define STATUS_PLACEHOLDER "$STATUS"
|
||||||
|
# define HTML_ERROR \
|
||||||
|
"<!DOCTYPE html>"\
|
||||||
|
"<html>"\
|
||||||
|
"<head>"\
|
||||||
|
"<title>" STATUS_PLACEHOLDER "</title>"\
|
||||||
|
"</head>"\
|
||||||
|
"<body>"\
|
||||||
|
"<h1 style=\"text-align:center\">" STATUS_PLACEHOLDER "</h1>"\
|
||||||
|
"<hr>"\
|
||||||
|
"<p style=\"text-align:center\">Le Webserv/0.1</p>"\
|
||||||
|
"</body>"\
|
||||||
|
"</html>"
|
||||||
|
|
||||||
|
// When new status added, need to update _init_http_status_map()
|
||||||
|
# define S200 "200 OK"
|
||||||
|
# define S201 "201 Created"
|
||||||
|
# define S204 "204 No Content"
|
||||||
|
|
||||||
|
# define S400 "400 Bad Request"
|
||||||
|
# define S403 "403 Forbidden"
|
||||||
|
# define S404 "404 Not Found"
|
||||||
|
# define S405 "405 Method Not Allowed"
|
||||||
|
# define S413 "413 Content Too Large"
|
||||||
|
|
||||||
|
# define S500 "500 Internal Server Error"
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -76,3 +76,134 @@ void Webserv::_listen(int socket_fd, unsigned int max_connections)
|
|||||||
throw std::runtime_error("Socket listen");
|
throw std::runtime_error("Socket listen");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Webserv::_init_http_status_map()
|
||||||
|
{
|
||||||
|
_http_status[200] = S200;
|
||||||
|
_http_status[201] = S201;
|
||||||
|
_http_status[204] = S204;
|
||||||
|
|
||||||
|
_http_status[400] = S400;
|
||||||
|
_http_status[403] = S403;
|
||||||
|
_http_status[404] = S404;
|
||||||
|
_http_status[405] = S405;
|
||||||
|
_http_status[413] = S413;
|
||||||
|
|
||||||
|
_http_status[500] = S500;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Webserv::_init_mime_types_map()
|
||||||
|
{
|
||||||
|
_mime_types[""] = "application/octet-stream";
|
||||||
|
|
||||||
|
_mime_types["html"] = "text/html";
|
||||||
|
_mime_types["htm"] = "text/html";
|
||||||
|
_mime_types["shtml"] = "text/html";
|
||||||
|
_mime_types["css"] = "text/css";
|
||||||
|
_mime_types["xml"] = "text/xml";
|
||||||
|
_mime_types["gif"] = "image/gif";
|
||||||
|
_mime_types["jpeg"] = "image/jpeg";
|
||||||
|
_mime_types["jpg"] = "image/jpeg";
|
||||||
|
_mime_types["js"] = "application/javascript";
|
||||||
|
_mime_types["atom"] = "application/atom+xml";
|
||||||
|
_mime_types["rss"] = "application/rss+xml";
|
||||||
|
|
||||||
|
_mime_types["mml"] = "text/mathml";
|
||||||
|
_mime_types["txt"] = "text/plain";
|
||||||
|
_mime_types["jad"] = "text/vnd.sun.j2me.app-descriptor";
|
||||||
|
_mime_types["wml"] = "text/vnd.wap.wml";
|
||||||
|
_mime_types["htc"] = "text/x-component";
|
||||||
|
|
||||||
|
_mime_types["png"] = "image/png";
|
||||||
|
_mime_types["tif"] = "image/tiff";
|
||||||
|
_mime_types["tiff"] = "image/tiff";
|
||||||
|
_mime_types["wbmp"] = "image/vnd.wap.wbmp";
|
||||||
|
_mime_types["ico"] = "image/x-icon";
|
||||||
|
_mime_types["jng"] = "image/x-jng";
|
||||||
|
_mime_types["bmp"] = "image/x-ms-bmp";
|
||||||
|
_mime_types["svg"] = "image/svg+xml";
|
||||||
|
_mime_types["svgz"] = "image/svg+xml";
|
||||||
|
_mime_types["webp"] = "image/webp";
|
||||||
|
|
||||||
|
_mime_types["woff"] = "application/font-woff";
|
||||||
|
_mime_types["jar"] = "application/java-archive";
|
||||||
|
_mime_types["war"] = "application/java-archive";
|
||||||
|
_mime_types["ear"] = "application/java-archive";
|
||||||
|
_mime_types["json"] = "application/json";
|
||||||
|
_mime_types["hqx"] = "application/mac-binhex40";
|
||||||
|
_mime_types["doc"] = "application/msword";
|
||||||
|
_mime_types["pdf"] = "application/pdf";
|
||||||
|
_mime_types["ps"] = "application/postscript";
|
||||||
|
_mime_types["eps"] = "application/postscript";
|
||||||
|
_mime_types["ai"] = "application/postscript";
|
||||||
|
_mime_types["rtf"] = "application/rtf";
|
||||||
|
_mime_types["m3u8"] = "application/vnd.apple.mpegurl";
|
||||||
|
_mime_types["xls"] = "application/vnd.ms-excel";
|
||||||
|
_mime_types["eot"] = "application/vnd.ms-fontobject";
|
||||||
|
_mime_types["ppt"] = "application/vnd.ms-powerpoint";
|
||||||
|
_mime_types["wmlc"] = "application/vnd.wap.wmlc";
|
||||||
|
_mime_types["kml"] = "application/vnd.google-earth.kml+xml";
|
||||||
|
_mime_types["kmz"] = "application/vnd.google-earth.kmz";
|
||||||
|
_mime_types["7z"] = "application/x-7z-compressed";
|
||||||
|
_mime_types["cco"] = "application/x-cocoa";
|
||||||
|
_mime_types["jardiff"] = "application/x-java-archive-diff";
|
||||||
|
_mime_types["jnlp"] = "application/x-java-jnlp-file";
|
||||||
|
_mime_types["run"] = "application/x-makeself";
|
||||||
|
_mime_types["pl"] = "application/x-perl";
|
||||||
|
_mime_types["pm"] = "application/x-perl";
|
||||||
|
_mime_types["prc"] = "application/x-pilot";
|
||||||
|
_mime_types["pdb"] = "application/x-pilot";
|
||||||
|
_mime_types["rar"] = "application/x-rar-compressed";
|
||||||
|
_mime_types["rpm"] = "application/x-redhat-package-manager";
|
||||||
|
_mime_types["sea"] = "application/x-sea";
|
||||||
|
_mime_types["swf"] = "application/x-shockwave-flash";
|
||||||
|
_mime_types["sit"] = "application/x-stuffit";
|
||||||
|
_mime_types["tcl"] = "application/x-tcl";
|
||||||
|
_mime_types["tk"] = "application/x-tcl";
|
||||||
|
_mime_types["der"] = "application/x-x509-ca-cert";
|
||||||
|
_mime_types["pem"] = "application/x-x509-ca-cert";
|
||||||
|
_mime_types["crt"] = "application/x-x509-ca-cert";
|
||||||
|
_mime_types["xpi"] = "application/x-xpinstall";
|
||||||
|
_mime_types["xhtml"] = "application/xhtml+xml";
|
||||||
|
_mime_types["xspf"] = "application/xspf+xml";
|
||||||
|
_mime_types["zip"] = "application/zip";
|
||||||
|
|
||||||
|
_mime_types["bin"] = "application/octet-stream";
|
||||||
|
_mime_types["exe"] = "application/octet-stream";
|
||||||
|
_mime_types["dll"] = "application/octet-stream";
|
||||||
|
_mime_types["deb"] = "application/octet-stream";
|
||||||
|
_mime_types["dmg"] = "application/octet-stream";
|
||||||
|
_mime_types["iso"] = "application/octet-stream";
|
||||||
|
_mime_types["img"] = "application/octet-stream";
|
||||||
|
_mime_types["msi"] = "application/octet-stream";
|
||||||
|
_mime_types["msp"] = "application/octet-stream";
|
||||||
|
_mime_types["msm"] = "application/octet-stream";
|
||||||
|
|
||||||
|
_mime_types["docx"] = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
|
||||||
|
_mime_types["xlsx"] = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
|
||||||
|
_mime_types["pptx"] = "application/vnd.openxmlformats-officedocument.presentationml.presentation";
|
||||||
|
|
||||||
|
_mime_types["mid"] = "audio/midi";
|
||||||
|
_mime_types["midi"] = "audio/midi";
|
||||||
|
_mime_types["kar"] = "audio/midi";
|
||||||
|
_mime_types["mp3"] = "audio/mpeg";
|
||||||
|
_mime_types["ogg"] = "audio/ogg";
|
||||||
|
_mime_types["m4a"] = "audio/x-m4a";
|
||||||
|
_mime_types["ra"] = "audio/x-realaudio";
|
||||||
|
|
||||||
|
_mime_types["3gpp"] = "video/3gpp";
|
||||||
|
_mime_types["3gp"] = "video/3gpp";
|
||||||
|
_mime_types["ts"] = "video/mp2t";
|
||||||
|
_mime_types["mp4"] = "video/mp4";
|
||||||
|
_mime_types["mpeg"] = "video/mpeg";
|
||||||
|
_mime_types["mpg"] = "video/mpeg";
|
||||||
|
_mime_types["mov"] = "video/quicktime";
|
||||||
|
_mime_types["webm"] = "video/webm";
|
||||||
|
_mime_types["flv"] = "video/x-flv";
|
||||||
|
_mime_types["m4v"] = "video/x-m4v";
|
||||||
|
_mime_types["mng"] = "video/x-mng";
|
||||||
|
_mime_types["asx"] = "video/x-ms-asf";
|
||||||
|
_mime_types["asf"] = "video/x-ms-asf";
|
||||||
|
_mime_types["wmv"] = "video/x-ms-wmv";
|
||||||
|
_mime_types["avi"] = "video/x-msvideo";
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,6 +3,8 @@
|
|||||||
|
|
||||||
void Webserv::_response(Client *client)
|
void Webserv::_response(Client *client)
|
||||||
{
|
{
|
||||||
|
client->status = 200; // default value
|
||||||
|
|
||||||
ServerConfig &server = _determine_process_server(client);
|
ServerConfig &server = _determine_process_server(client);
|
||||||
_send_response(client, server);
|
_send_response(client, server);
|
||||||
if (g_last_signal)
|
if (g_last_signal)
|
||||||
@@ -14,9 +16,12 @@ void Webserv::_send_response(Client *client, ServerConfig &server)
|
|||||||
ssize_t ret;
|
ssize_t ret;
|
||||||
|
|
||||||
std::cerr << "send()\n";
|
std::cerr << "send()\n";
|
||||||
// std::cerr << "RAW_REQUEST\n|\n" << client->raw_request << "|\n"; // DEBUG
|
|
||||||
|
|
||||||
|
_append_base_headers(client);
|
||||||
_construct_response(client, server);
|
_construct_response(client, server);
|
||||||
|
_insert_status_line(client);
|
||||||
|
if (client->status >= 400)
|
||||||
|
_error_html_response(client, server);
|
||||||
|
|
||||||
ret = ::send(client->fd, client->response.c_str(), client->response.size(), 0);
|
ret = ::send(client->fd, client->response.c_str(), client->response.size(), 0);
|
||||||
if (ret == -1)
|
if (ret == -1)
|
||||||
@@ -27,30 +32,51 @@ void Webserv::_send_response(Client *client, ServerConfig &server)
|
|||||||
return ;
|
return ;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (client->raw_request.find("Connection: close") != std::string::npos)
|
// Body send (WIP for working binary files)
|
||||||
|
if (client->body_size)
|
||||||
|
{
|
||||||
|
ret = ::send(client->fd, client->buf, client->body_size, 0);
|
||||||
|
if (ret == -1)
|
||||||
|
{
|
||||||
|
std::perror("err send()");
|
||||||
|
std::cerr << "client.fd =" << client->fd << "\n"; // DEBUG
|
||||||
|
_close_client(client->fd);
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (client->get_headers("Connection") == "close")
|
||||||
_close_client(client->fd);
|
_close_client(client->fd);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_epoll_update(client->fd, EPOLLIN, EPOLL_CTL_MOD);
|
_epoll_update(client->fd, EPOLLIN, EPOLL_CTL_MOD);
|
||||||
client->raw_request.clear();
|
client->clear();
|
||||||
client->response.clear();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Webserv::_append_base_headers(Client *client)
|
||||||
|
{
|
||||||
|
client->response.append("Server: Webserv/0.1" CRLF);
|
||||||
|
|
||||||
|
if (client->get_headers("Connection") == "close")
|
||||||
|
client->response.append("Connection: close" CRLF);
|
||||||
|
else
|
||||||
|
client->response.append("Connection: keep-alive" CRLF);
|
||||||
|
}
|
||||||
|
|
||||||
void Webserv::_construct_response(Client *client, ServerConfig &server)
|
void Webserv::_construct_response(Client *client, ServerConfig &server)
|
||||||
{
|
{
|
||||||
|
if (client->get_body().size() > server.client_body_limit)
|
||||||
|
{
|
||||||
|
client->status = 413;
|
||||||
|
return;
|
||||||
|
}
|
||||||
LocationConfig &location = _determine_location(server, client->get_path());
|
LocationConfig &location = _determine_location(server, client->get_path());
|
||||||
|
_process_method(client, server, location);
|
||||||
|
}
|
||||||
|
|
||||||
client->status = 200; // default value
|
void Webserv::_process_method(Client *client, ServerConfig &server, LocationConfig &location)
|
||||||
|
{
|
||||||
client->response.append("Server: Webserv/0.1\r\n");
|
|
||||||
|
|
||||||
if (client->get_headers("Connection") == "close")
|
|
||||||
client->response.append("Connection: close\r\n");
|
|
||||||
else
|
|
||||||
client->response.append("Connection: keep-alive\r\n");
|
|
||||||
|
|
||||||
|
|
||||||
unsigned int allow_methods = ALL_METHODS; // TEMP VARIABLE
|
unsigned int allow_methods = ALL_METHODS; // TEMP VARIABLE
|
||||||
// after update in ConfigParser, use the "allow_methods" of location.
|
// after update in ConfigParser, use the "allow_methods" of location.
|
||||||
// TODO in ConfigParser : by default if no field in config file, "allow_methods" must be set to ALL_METHODS
|
// TODO in ConfigParser : by default if no field in config file, "allow_methods" must be set to ALL_METHODS
|
||||||
@@ -61,72 +87,61 @@ void Webserv::_construct_response(Client *client, ServerConfig &server)
|
|||||||
}
|
}
|
||||||
else if (allow_methods & client->get_method())
|
else if (allow_methods & client->get_method())
|
||||||
{
|
{
|
||||||
if (client->get_method() & GET)
|
switch (client->get_method())
|
||||||
_get_ressource(client, server, location);
|
{
|
||||||
else if (client->get_method() & POST)
|
case (GET):
|
||||||
_post(client, server, location);
|
_get(client, server, location);
|
||||||
else if (client->get_method() & DELETE)
|
break;
|
||||||
_delete(client, server, location);
|
case (POST):
|
||||||
|
_post(client, server, location);
|
||||||
|
break;
|
||||||
|
case (DELETE):
|
||||||
|
_delete(client, server, location);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
client->status = 405;
|
client->status = 405;
|
||||||
client->response.append("Allow: ");
|
client->response.append("Allow: ");
|
||||||
client->response.append(::http_methods_to_str(allow_methods));
|
client->response.append(::http_methods_to_str(allow_methods));
|
||||||
client->response.append("\r\n");
|
client->response.append(CRLF);
|
||||||
}
|
}
|
||||||
|
|
||||||
_insert_status_line(client, server);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
|
void Webserv::_insert_status_line(Client *client)
|
||||||
#define HTML_ERROR(STATUS) "\r\n<!DOCTYPE html><html><head><title>"STATUS"</title></head><body><h1 style=\"text-align:center\">"STATUS"</h1><hr><p style=\"text-align:center\">Le Webserv/0.1</p></body></html>"
|
|
||||||
#define S200 "200 OK"
|
|
||||||
#define S400 "400 Bad Request"
|
|
||||||
#define S404 "404 Not Found"
|
|
||||||
#define S500 "500 Internal Server Error"
|
|
||||||
void Webserv::_insert_status_line(Client *client, ServerConfig &server)
|
|
||||||
{
|
{
|
||||||
std::string status_line;
|
std::string status_line;
|
||||||
|
|
||||||
status_line.append("HTTP/1.1 ");
|
status_line.append("HTTP/1.1 ");
|
||||||
// WIP, maybe make a map for status response
|
status_line.append(_http_status[client->status]);
|
||||||
switch (client->status)
|
status_line.append(CRLF);
|
||||||
{
|
|
||||||
case (200):
|
|
||||||
status_line.append(S200);
|
|
||||||
break;
|
|
||||||
case (400):
|
|
||||||
status_line.append(S400);
|
|
||||||
client->response.append(HTML_ERROR(S400));
|
|
||||||
break;
|
|
||||||
case (404):
|
|
||||||
status_line.append(S404);
|
|
||||||
client->response.append(HTML_ERROR(S404));
|
|
||||||
break;
|
|
||||||
case (500):
|
|
||||||
status_line.append(S500);
|
|
||||||
client->response.append(HTML_ERROR(S500));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
status_line.append("\r\n");
|
|
||||||
|
|
||||||
client->response.insert(0, status_line);
|
client->response.insert(0, status_line);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define ROOT "www"
|
void Webserv::_error_html_response(Client *client, ServerConfig &server)
|
||||||
#define INDEX "index.html"
|
|
||||||
#define MAX_FILESIZE 1000000 // (1Mo)
|
|
||||||
void Webserv::_get_ressource(Client *client, ServerConfig &server, LocationConfig &location)
|
|
||||||
{
|
{
|
||||||
std::ifstream ifd; // For chunk, ifstream directly in struct CLient for multiples read without close() ?
|
if (server.error_pages[client->status].empty())
|
||||||
char buf[MAX_FILESIZE+1];
|
{
|
||||||
std::string tmp;
|
std::string html_page = HTML_ERROR;
|
||||||
|
::replace_all_substr(html_page, STATUS_PLACEHOLDER, _http_status[client->status]);
|
||||||
|
_append_body(client, html_page.c_str(), html_page.size(), "html");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
_get_file(client, server.error_pages[client->status]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define INDEX "index.html" // temp wip
|
||||||
|
void Webserv::_get(Client *client, ServerConfig &server, LocationConfig &location)
|
||||||
|
{
|
||||||
|
(void)server; // To remove from arg if we determine its useless
|
||||||
std::string path = client->get_path();
|
std::string path = client->get_path();
|
||||||
|
|
||||||
if (path == "/") // TODO ; With server config
|
if (path == "/") // TODO : index and autoindex
|
||||||
path.append(INDEX);
|
path.append(INDEX);
|
||||||
path.insert(0, ROOT);
|
path.insert(0, location.root);
|
||||||
|
|
||||||
std::cerr << "path = " << path << "\n";
|
std::cerr << "path = " << path << "\n";
|
||||||
|
|
||||||
@@ -140,24 +155,39 @@ void Webserv::_get_ressource(Client *client, ServerConfig &server, LocationConfi
|
|||||||
//
|
//
|
||||||
// END TMP HUGO
|
// END TMP HUGO
|
||||||
|
|
||||||
|
_get_file(client, path);
|
||||||
if (access(path.c_str(), R_OK) == -1)
|
}
|
||||||
|
|
||||||
|
void Webserv::_get_file(Client *client, const std::string &path)
|
||||||
|
{
|
||||||
|
std::ifstream ifd; // For chunk, ifstream directly in struct CLient for multiples read without close() ?
|
||||||
|
// char buf[MAX_FILESIZE+1];
|
||||||
|
|
||||||
|
if (access(path.c_str(), F_OK) == -1)
|
||||||
{
|
{
|
||||||
std::perror("err access()");
|
std::perror("err access()");
|
||||||
client->status = 404;
|
client->status = 404;
|
||||||
return ;
|
return ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (access(path.c_str(), R_OK) == -1)
|
||||||
|
{
|
||||||
|
std::perror("err access()");
|
||||||
|
client->status = 403;
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
|
||||||
ifd.open(path.c_str(), std::ios::binary | std::ios::ate); // std::ios::binary (binary for files like images ?)
|
ifd.open(path.c_str(), std::ios::binary | std::ios::ate); // std::ios::binary (binary for files like images ?)
|
||||||
if (!ifd)
|
if (!ifd)
|
||||||
{
|
{
|
||||||
std::cerr << path << ": open fail" << '\n';
|
std::cerr << path << ": ifd.open fail" << '\n';
|
||||||
client->status = 500;
|
client->status = 500;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// WIP : Chunk or not chunk (if filesize too big)
|
|
||||||
std::streampos size = ifd.tellg();
|
std::streampos size = ifd.tellg();
|
||||||
|
|
||||||
|
// WIP : Chunk or not chunk (if filesize too big)
|
||||||
if (size > MAX_FILESIZE)
|
if (size > MAX_FILESIZE)
|
||||||
{
|
{
|
||||||
// Then chunk
|
// Then chunk
|
||||||
@@ -168,38 +198,161 @@ void Webserv::_get_ressource(Client *client, ServerConfig &server, LocationConfi
|
|||||||
}
|
}
|
||||||
|
|
||||||
ifd.seekg(0, std::ios::beg);
|
ifd.seekg(0, std::ios::beg);
|
||||||
ifd.read(buf, size);
|
ifd.read(client->buf, size);
|
||||||
buf[ifd.gcount()] = '\0';
|
if (!ifd)
|
||||||
|
{
|
||||||
|
std::cerr << path << ": ifd.read fail" << '\n';
|
||||||
|
client->status = 500;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
client->status = 200;
|
||||||
|
client->buf[ifd.gcount()] = '\0';
|
||||||
|
|
||||||
client->response.append("Content-Type: text/html; charset=UTF-8\r\n"); // TODO : determine Content-Type
|
std::string file_ext = "";
|
||||||
|
size_t dot_pos = path.rfind(".");
|
||||||
|
std::cerr << "dot_pos = " << dot_pos << "\n";
|
||||||
|
if (dot_pos != std::string::npos && dot_pos + 1 < path.size())
|
||||||
|
file_ext = path.substr(dot_pos + 1);
|
||||||
|
std::cerr << "file_ext = " << file_ext << "\n";
|
||||||
|
|
||||||
client->response.append("Content-Length: ");
|
client->body_size = ifd.gcount();
|
||||||
tmp = ::itos(ifd.gcount());
|
// WIP, pass empty body argument because append to string mess up binary file
|
||||||
client->response.append(tmp);
|
_append_body(client, "", client->body_size, file_ext);
|
||||||
client->response.append("\r\n");
|
}
|
||||||
|
|
||||||
// Body
|
|
||||||
client->response.append("\r\n");
|
|
||||||
client->response.append(buf);
|
|
||||||
|
|
||||||
ifd.close();
|
ifd.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Webserv::_post(Client *client, ServerConfig &server, LocationConfig &location)
|
void Webserv::_append_body(Client *client, const char *body, size_t body_size, const std::string &file_extension)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
TODO
|
TODO : determine Content-Type
|
||||||
|
how ? read the body ?
|
||||||
|
or before in other way (like based and file extension) and pass here as argument ?
|
||||||
|
http://nginx.org/en/docs/http/ngx_http_core_module.html#types
|
||||||
|
Need to look "conf/mime.types" of nginx. Maybe make a map<> based on that.
|
||||||
*/
|
*/
|
||||||
(void)0;
|
const std::string &mime_type = _mime_types[file_extension];
|
||||||
|
client->response.append("Content-Type: ");
|
||||||
|
client->response.append(mime_type);
|
||||||
|
if (mime_type.find("text/") != std::string::npos)
|
||||||
|
client->response.append("; charset=UTF-8");
|
||||||
|
client->response.append(CRLF);
|
||||||
|
|
||||||
|
client->response.append("Content-Length: ");
|
||||||
|
std::string tmp = ::itos(body_size);
|
||||||
|
client->response.append(tmp);
|
||||||
|
client->response.append(CRLF);
|
||||||
|
|
||||||
|
client->response.append(CRLF);
|
||||||
|
client->response.append(body);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Webserv::_post(Client *client, ServerConfig &server, LocationConfig &location)
|
||||||
|
{
|
||||||
|
(void)server; // To remove from arg if we determine its useless
|
||||||
|
/*
|
||||||
|
WIP
|
||||||
|
https://www.rfc-editor.org/rfc/rfc9110.html#name-post
|
||||||
|
*/
|
||||||
|
std::string path = client->get_path();
|
||||||
|
path.insert(0, location.root);
|
||||||
|
|
||||||
|
/* CGI Here ? */
|
||||||
|
|
||||||
|
_post_file(client, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Webserv::_post_file(Client *client, const std::string &path)
|
||||||
|
{
|
||||||
|
std::ofstream ofd;
|
||||||
|
|
||||||
|
bool file_existed;
|
||||||
|
if (access(path.c_str(), F_OK) == -1)
|
||||||
|
file_existed = false;
|
||||||
|
else
|
||||||
|
file_existed = true;
|
||||||
|
|
||||||
|
// How to determine status 403 for file that dont already exist ?
|
||||||
|
if (file_existed && access(path.c_str(), W_OK) == -1)
|
||||||
|
{
|
||||||
|
std::perror("err access()");
|
||||||
|
client->status = 403;
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
|
||||||
|
ofd.open(path.c_str(), std::ios::binary | std::ios::trunc);
|
||||||
|
if (!ofd)
|
||||||
|
{
|
||||||
|
std::cerr << path << ": ofd.open fail" << '\n';
|
||||||
|
client->status = 500;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Used body.size() so Content-Length useless at this point ?
|
||||||
|
// Maybe usefull in _read_request() for rejecting too big content.
|
||||||
|
// Need to _determine_process_server() as soon as possible,
|
||||||
|
// like in _read_request() for stopping read if body is too big ?
|
||||||
|
ofd.write(client->get_body().c_str(), client->get_body().size());
|
||||||
|
if (!ofd)
|
||||||
|
{
|
||||||
|
std::cerr << path << ": ofd.write fail" << '\n';
|
||||||
|
client->status = 500;
|
||||||
|
}
|
||||||
|
else if (file_existed)
|
||||||
|
{
|
||||||
|
client->status = 200;
|
||||||
|
// WIP https://www.rfc-editor.org/rfc/rfc9110.html#name-200-ok
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
client->status = 201;
|
||||||
|
// WIP https://www.rfc-editor.org/rfc/rfc9110.html#section-9.3.3-4
|
||||||
|
}
|
||||||
|
|
||||||
|
ofd.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Webserv::_delete(Client *client, ServerConfig &server, LocationConfig &location)
|
void Webserv::_delete(Client *client, ServerConfig &server, LocationConfig &location)
|
||||||
{
|
{
|
||||||
|
(void)server; // To remove from arg if we determine its useless
|
||||||
/*
|
/*
|
||||||
TODO
|
WIP
|
||||||
|
https://www.rfc-editor.org/rfc/rfc9110.html#name-delete
|
||||||
*/
|
*/
|
||||||
(void)0;
|
std::string path = client->get_path();
|
||||||
|
path.insert(0, location.root);
|
||||||
|
|
||||||
|
/* CGI Here ? */
|
||||||
|
|
||||||
|
_delete_file(client, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Webserv::_delete_file(Client *client, const std::string &path)
|
||||||
|
{
|
||||||
|
if (access(path.c_str(), F_OK) == -1)
|
||||||
|
{
|
||||||
|
std::perror("err access()");
|
||||||
|
client->status = 404;
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (access(path.c_str(), W_OK) == -1)
|
||||||
|
{
|
||||||
|
std::perror("err access()");
|
||||||
|
client->status = 403;
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (remove(path.c_str()) == -1)
|
||||||
|
{
|
||||||
|
std::perror("err remove()");
|
||||||
|
client->status = 500;
|
||||||
|
return ;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ServerConfig &Webserv::_determine_process_server(Client *client)
|
ServerConfig &Webserv::_determine_process_server(Client *client)
|
||||||
|
|||||||
BIN
www/drill.jpg
Normal file
BIN
www/drill.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 16 KiB |
BIN
www/favicon.ico
Normal file
BIN
www/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.2 KiB |
BIN
www/kermit.ico
Normal file
BIN
www/kermit.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.2 KiB |
@@ -13,7 +13,7 @@
|
|||||||
<link rel="alternative stylesheet" type="text/css" href="./rfc2119_files/errata-monochrome.css" title="Monochrome">
|
<link rel="alternative stylesheet" type="text/css" href="./rfc2119_files/errata-monochrome.css" title="Monochrome">
|
||||||
<link rel="alternative stylesheet" type="text/css" href="./rfc2119_files/errata-printer.css" title="Printer">
|
<link rel="alternative stylesheet" type="text/css" href="./rfc2119_files/errata-printer.css" title="Printer">
|
||||||
|
|
||||||
<script src="./rfc2119_files/errata.js.téléchargement"></script>
|
<script src="./rfc2119_files/errata.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="Verified-headnote-styling">
|
<div class="Verified-headnote-styling">
|
||||||
@@ -309,4 +309,4 @@ Full stop should appear outside the parentheses in the last sentence.
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
</pre></body></html>
|
</pre></body></html>
|
||||||
139
www/rfc2119_files/errata-base.css
Normal file
139
www/rfc2119_files/errata-base.css
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
<style type="text/css">
|
||||||
|
@media only screen
|
||||||
|
and (min-width: 992px)
|
||||||
|
and (max-width: 1199px) {
|
||||||
|
body { font-size: 14pt; }
|
||||||
|
div.content { width: 96ex; margin: 0 auto; }
|
||||||
|
}
|
||||||
|
@media only screen
|
||||||
|
and (min-width: 768px)
|
||||||
|
and (max-width: 991px) {
|
||||||
|
body { font-size: 14pt; }
|
||||||
|
div.content { width: 96ex; margin: 0 auto; }
|
||||||
|
}
|
||||||
|
@media only screen
|
||||||
|
and (min-width: 480px)
|
||||||
|
and (max-width: 767px) {
|
||||||
|
body { font-size: 11pt; }
|
||||||
|
div.content { width: 96ex; margin: 0 auto; }
|
||||||
|
}
|
||||||
|
@media only screen
|
||||||
|
and (max-width: 479px) {
|
||||||
|
body { font-size: 8pt; }
|
||||||
|
div.content { width: 96ex; margin: 0 auto; }
|
||||||
|
}
|
||||||
|
@media only screen
|
||||||
|
and (min-device-width : 375px)
|
||||||
|
and (max-device-width : 667px) {
|
||||||
|
body { font-size: 9.5pt; }
|
||||||
|
div.content { width: 96ex; margin: 0; }
|
||||||
|
}
|
||||||
|
@media only screen
|
||||||
|
and (min-device-width: 1200px) {
|
||||||
|
body { font-size: 10pt; margin: 0 4em; }
|
||||||
|
div.content { width: 96ex; margin: 0; }
|
||||||
|
}
|
||||||
|
h1, h2, h3, h4, h5, h6, .h1, .h2, .h3, .h4, .h5, .h6 {
|
||||||
|
font-weight: bold;
|
||||||
|
line-height: 0pt;
|
||||||
|
display: inline;
|
||||||
|
white-space: pre;
|
||||||
|
font-family: monospace;
|
||||||
|
font-size: 1em;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
pre {
|
||||||
|
font-size: 1em;
|
||||||
|
margin-top: 0px;
|
||||||
|
margin-bottom: 0px;
|
||||||
|
}
|
||||||
|
.pre {
|
||||||
|
white-space: pre;
|
||||||
|
font-family: monospace;
|
||||||
|
}
|
||||||
|
.header{
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.newpage {
|
||||||
|
page-break-before: always;
|
||||||
|
}
|
||||||
|
.invisible {
|
||||||
|
text-decoration: none;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
a.selflink {
|
||||||
|
color: black;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
@media print {
|
||||||
|
body {
|
||||||
|
font-family: monospace;
|
||||||
|
font-size: 10.5pt;
|
||||||
|
}
|
||||||
|
h1, h2, h3, h4, h5, h6 {
|
||||||
|
font-size: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:link, a:visited {
|
||||||
|
color: inherit;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
.noprint {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media screen {
|
||||||
|
.grey, .grey a:link, .grey a:visited {
|
||||||
|
color: #777;
|
||||||
|
}
|
||||||
|
.docinfo {
|
||||||
|
background-color: #EEE;
|
||||||
|
}
|
||||||
|
.top {
|
||||||
|
border-top: 7px solid #EEE;
|
||||||
|
}
|
||||||
|
.bgwhite { background-color: white; }
|
||||||
|
.bgred { background-color: #F44; }
|
||||||
|
.bggrey { background-color: #666; }
|
||||||
|
.bgbrown { background-color: #840; }
|
||||||
|
.bgorange { background-color: #FA0; }
|
||||||
|
.bgyellow { background-color: #EE0; }
|
||||||
|
.bgmagenta{ background-color: #F4F; }
|
||||||
|
.bgblue { background-color: #66F; }
|
||||||
|
.bgcyan { background-color: #4DD; }
|
||||||
|
.bggreen { background-color: #4F4; }
|
||||||
|
|
||||||
|
.legend { font-size: 90%; }
|
||||||
|
.cplate { font-size: 70%; border: solid grey 1px; }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.Verified-headnote-styling, .Held-headnote-styling, .Reported-headnote-styling, .Rejected-headnote-styling {
|
||||||
|
border:dashed;
|
||||||
|
margin:8px;
|
||||||
|
padding;24px;
|
||||||
|
overflow-wrap: normal;
|
||||||
|
padding: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Verified-endnote-styling, .Held-endnote-styling, .Reported-endnote-styling, .Rejected-endnote-styling {
|
||||||
|
border:dashed;
|
||||||
|
margin:8px;
|
||||||
|
padding:24px;
|
||||||
|
overflow:auto;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Verified-ineline-styling, .Held-ineline-styling, .Reported-ineline-styling, .Rejected-ineline-styling {
|
||||||
|
white-space: pre-wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nodeCloseClass {
|
||||||
|
display:none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nodeOpenClass {
|
||||||
|
display:inline;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
43
www/rfc2119_files/errata-color.css
Normal file
43
www/rfc2119_files/errata-color.css
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
<style type="text/css">
|
||||||
|
.verified {color: green}
|
||||||
|
.supplementary-styling {
|
||||||
|
background-color: yellow
|
||||||
|
}
|
||||||
|
.old-text {color: red}
|
||||||
|
|
||||||
|
.Verified-headnote-styling, .Verified-endnote-styling {
|
||||||
|
background-color: LightGreen;
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Verified-inline-styling {
|
||||||
|
color: Green;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Held-headnote-styling, .Held-endnote-styling {
|
||||||
|
background-color: LightBlue;
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Held-inline-styling {
|
||||||
|
color: Blue;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Reported-headnote-styling, .Reported-endnote-styling {
|
||||||
|
background-color: Beige;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Reported-inline-styling {
|
||||||
|
color:GoldenRod;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Rejected-headnote-styling, .Rejected-endnote-styling {
|
||||||
|
background-color: LightPink;
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Rejected-inline-styling {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
34
www/rfc2119_files/errata-monochrome.css
Normal file
34
www/rfc2119_files/errata-monochrome.css
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
<style type="text/css">
|
||||||
|
.Verified-headnote-styling, .Verified-endnote-styling {
|
||||||
|
font-wieght: bold;
|
||||||
|
}
|
||||||
|
.Verified-inline-styling {
|
||||||
|
font-wieght: bold;
|
||||||
|
background-color: lightGrey;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Held-headnote-styling, .Held-endnote-styling {
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Held-inline-styling {
|
||||||
|
font-style: italic;
|
||||||
|
background-color: lightGrey;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Reported-headnote-styling, .Reported-endnote-styling {
|
||||||
|
background-color: Beige;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Reported-inline-styling {
|
||||||
|
color: Yellow;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Rejected-headnote-styling, .Rejected-endnote-styling {
|
||||||
|
background-color: LightPink;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Rejected-inline-styling {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
43
www/rfc2119_files/errata-printer.css
Normal file
43
www/rfc2119_files/errata-printer.css
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
<style type="text/css">
|
||||||
|
.Verified-headnote-styling, .Verified-endnote-styling {
|
||||||
|
font-wieght: bold;
|
||||||
|
}
|
||||||
|
.Verified-inline-styling {
|
||||||
|
font-wieght: bold;
|
||||||
|
background-color: lightGrey;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Held-headnote-styling, .Held-endnote-styling {
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Held-inline-styling {
|
||||||
|
font-style: italic;
|
||||||
|
background-color: lightGrey;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Reported-headnote-styling, .Reported-endnote-styling {
|
||||||
|
background-color: Beige;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Reported-inline-styling {
|
||||||
|
color: Yellow;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Rejected-headnote-styling, .Rejected-endnote-styling {
|
||||||
|
background-color: LightPink;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Rejected-inline-styling {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nodeCloseClass {
|
||||||
|
display:inline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nodeOpenClass {
|
||||||
|
display:inline;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
4
www/rfc2119_files/errata.js
Normal file
4
www/rfc2119_files/errata.js
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
function hideFunction(nodeId) {
|
||||||
|
var ul = document.getElementById(nodeId)
|
||||||
|
ul.className = (ul.className=="nodeOpenClass") ? "nodeCloseClass" : "nodeOpenClass"
|
||||||
|
}
|
||||||
4
www/rfc2119_files/errata.js.téléchargement
Normal file
4
www/rfc2119_files/errata.js.téléchargement
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
function hideFunction(nodeId) {
|
||||||
|
var ul = document.getElementById(nodeId)
|
||||||
|
ul.className = (ul.className=="nodeOpenClass") ? "nodeCloseClass" : "nodeOpenClass"
|
||||||
|
}
|
||||||
@@ -1,300 +0,0 @@
|
|||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
|
||||||
<!-- saved from url=(0057)https://www.rfc-editor.org/rfc/inline-errata/rfc2119.html -->
|
|
||||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"><head profile="http://dublincore.org/documents/2008/08/04/dc-html/"><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
|
||||||
<title>rfc2119</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="Verified-headnote-styling">
|
|
||||||
<span style="font-weight: bold;">This is a purely informative rendering of an RFC that includes verified errata. This rendering may not be used as a reference.</span>
|
|
||||||
<br>
|
|
||||||
<br>
|
|
||||||
The following 'Verified' errata have been incorporated in this document:
|
|
||||||
<a href="https://www.rfc-editor.org/rfc/inline-errata/rfc2119.html#eid493">EID 493</a>, <a href="https://www.rfc-editor.org/rfc/inline-errata/rfc2119.html#btn_494">EID 494</a>, <a href="https://www.rfc-editor.org/rfc/inline-errata/rfc2119.html#btn_495">EID 495</a>, <a href="https://www.rfc-editor.org/rfc/inline-errata/rfc2119.html#btn_494">EID 496</a>, <a href="https://www.rfc-editor.org/rfc/inline-errata/rfc2119.html#eid498">EID 498</a>, <a href="https://www.rfc-editor.org/rfc/inline-errata/rfc2119.html#btn_499">EID 499</a>, <a href="https://www.rfc-editor.org/rfc/inline-errata/rfc2119.html#eid500">EID 500</a>, <a href="https://www.rfc-editor.org/rfc/inline-errata/rfc2119.html#btn_5101">EID 5101</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<pre>Network Working Group S. Bradner
|
|
||||||
Request for Comments: 2119 Harvard University
|
|
||||||
BCP: 14 March 1997
|
|
||||||
Category: Best Current Practice
|
|
||||||
|
|
||||||
|
|
||||||
Key words for use in RFCs to Indicate Requirement Levels
|
|
||||||
|
|
||||||
Status of this Memo
|
|
||||||
|
|
||||||
This document specifies an Internet Best Current Practices for the
|
|
||||||
Internet Community, and requests discussion and suggestions for
|
|
||||||
improvements. Distribution of this memo is unlimited.
|
|
||||||
|
|
||||||
Abstract
|
|
||||||
|
|
||||||
In many standards track documents several words are used to signify
|
|
||||||
the requirements in the specification. These words are often
|
|
||||||
capitalized. This document defines these words as they should be
|
|
||||||
interpreted in IETF documents. Authors who follow these guidelines
|
|
||||||
should incorporate this phrase near the beginning of their document:
|
|
||||||
|
|
||||||
<span class="Verified-inline-styling" id="inline-499"> The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL <button id="btn_499" target="expand_499" onclick="hideFunction("expand_499")">Expand</button>
|
|
||||||
NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT
|
|
||||||
RECOMMENDED", "MAY", and "OPTIONAL" in this document are to
|
|
||||||
be interpreted as described in RFC 2119.</span>
|
|
||||||
<div class="nodeCloseClass" id="expand_499"><div class="Verified-endnote-styling" id="eid499">
|
|
||||||
<pre><b><i><a href="https://www.rfc-editor.org/errata/eid499">EID 499</a> (Verified) is as follows:</i></b>
|
|
||||||
|
|
||||||
<b>Section:</b> Abstract
|
|
||||||
|
|
||||||
<b>Original Text:</b>
|
|
||||||
|
|
||||||
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL
|
|
||||||
NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and
|
|
||||||
"OPTIONAL" in this document are to be interpreted as described in
|
|
||||||
RFC 2119.
|
|
||||||
|
|
||||||
<b>Corrected Text:</b>
|
|
||||||
|
|
||||||
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL
|
|
||||||
NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT
|
|
||||||
RECOMMENDED", "MAY", and "OPTIONAL" in this document are to
|
|
||||||
be interpreted as described in RFC 2119.
|
|
||||||
</pre>
|
|
||||||
<b>Notes:</b><br>
|
|
||||||
The phrase "NOT RECOMMENDED" is missing from this sentence.
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
Note that the force of these words is modified by the requirement
|
|
||||||
level of the document in which they are used.
|
|
||||||
|
|
||||||
<span class="Verified-inline-styling" id="inline-495">1. MUST This word, or the terms "REQUIRED" or "SHALL", means that the <button id="btn_495" target="expand_495" onclick="hideFunction("expand_495")">Expand</button>
|
|
||||||
definition is an absolute requirement of the specification.
|
|
||||||
<div class="Verified-endnote-styling" id="eid493">
|
|
||||||
<pre><b><i><a href="https://www.rfc-editor.org/errata/eid493">EID 493</a> (Verified) is as follows:</i></b>
|
|
||||||
|
|
||||||
<b>Section:</b> 1
|
|
||||||
|
|
||||||
<b>Original Text:</b>
|
|
||||||
|
|
||||||
2. MUST NOT This phrase, or the phrase "SHALL NOT", mean that the
|
|
||||||
definition is an absolute prohibition of the specification.
|
|
||||||
|
|
||||||
<b>Corrected Text:</b>
|
|
||||||
|
|
||||||
2. MUST NOT This phrase, or the phrase "SHALL NOT", means that the
|
|
||||||
definition is an absolute prohibition of the specification.
|
|
||||||
</pre>
|
|
||||||
<b>Notes:</b><br>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<div class="Verified-endnote-styling" id="eid498">
|
|
||||||
<pre><b><i><a href="https://www.rfc-editor.org/errata/eid498">EID 498</a> (Verified) is as follows:</i></b>
|
|
||||||
|
|
||||||
<b>Section:</b> 1
|
|
||||||
|
|
||||||
<b>Original Text:</b>
|
|
||||||
|
|
||||||
4. SHOULD NOT This phrase, or the phrase "NOT RECOMMENDED" mean that
|
|
||||||
there may exist valid reasons in particular circumstances when the
|
|
||||||
particular behavior is acceptable or even useful, but the full
|
|
||||||
implications should be understood and the case carefully weighed
|
|
||||||
before implementing any behavior described with this label.
|
|
||||||
|
|
||||||
<b>Corrected Text:</b>
|
|
||||||
|
|
||||||
4. SHOULD NOT This phrase, or the phrase "NOT RECOMMENDED", means that
|
|
||||||
there may exist valid reasons in particular circumstances when the
|
|
||||||
particular behavior is acceptable or even useful, but the full
|
|
||||||
implications should be understood and the case carefully weighed
|
|
||||||
before implementing any behavior described with this label.
|
|
||||||
</pre>
|
|
||||||
<b>Notes:</b><br>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<div class="Verified-endnote-styling" id="eid500">
|
|
||||||
<pre><b><i><a href="https://www.rfc-editor.org/errata/eid500">EID 500</a> (Verified) is as follows:</i></b>
|
|
||||||
|
|
||||||
<b>Section:</b> 1
|
|
||||||
|
|
||||||
<b>Original Text:</b>
|
|
||||||
|
|
||||||
3. SHOULD This word, or the adjective "RECOMMENDED", mean that there
|
|
||||||
may exist valid reasons in particular circumstances to ignore a
|
|
||||||
particular item, but the full implications must be understood and
|
|
||||||
carefully weighed before choosing a different course.
|
|
||||||
|
|
||||||
<b>Corrected Text:</b>
|
|
||||||
|
|
||||||
3. SHOULD This word, or the adjective "RECOMMENDED", means that there
|
|
||||||
may exist valid reasons in particular circumstances to ignore a
|
|
||||||
particular item, but the full implications must be understood and
|
|
||||||
carefully weighed before choosing a different course.
|
|
||||||
</pre>
|
|
||||||
<b>Notes:</b><br>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</span>
|
|
||||||
<div class="nodeCloseClass" id="expand_495"><div class="Verified-endnote-styling" id="eid495">
|
|
||||||
<pre><b><i><a href="https://www.rfc-editor.org/errata/eid495">EID 495</a> (Verified) is as follows:</i></b>
|
|
||||||
|
|
||||||
<b>Section:</b> 1
|
|
||||||
|
|
||||||
<b>Original Text:</b>
|
|
||||||
|
|
||||||
1. MUST This word, or the terms "REQUIRED" or "SHALL", mean that the
|
|
||||||
definition is an absolute requirement of the specification.
|
|
||||||
|
|
||||||
|
|
||||||
<b>Corrected Text:</b>
|
|
||||||
|
|
||||||
1. MUST This word, or the terms "REQUIRED" or "SHALL", means that the
|
|
||||||
definition is an absolute requirement of the specification.
|
|
||||||
</pre>
|
|
||||||
<b>Notes:</b><br>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
2. MUST NOT This phrase, or the phrase "SHALL NOT", mean that the
|
|
||||||
definition is an absolute prohibition of the specification.
|
|
||||||
|
|
||||||
3. SHOULD This word, or the adjective "RECOMMENDED", mean that there
|
|
||||||
may exist valid reasons in particular circumstances to ignore a
|
|
||||||
particular item, but the full implications must be understood and
|
|
||||||
carefully weighed before choosing a different course.
|
|
||||||
|
|
||||||
4. SHOULD NOT This phrase, or the phrase "NOT RECOMMENDED" mean that
|
|
||||||
there may exist valid reasons in particular circumstances when the
|
|
||||||
particular behavior is acceptable or even useful, but the full
|
|
||||||
implications should be understood and the case carefully weighed
|
|
||||||
before implementing any behavior described with this label.
|
|
||||||
|
|
||||||
<span class="Verified-inline-styling" id="inline-5101">5. MAY This word, or the adjective "OPTIONAL", mean that an item is <button id="btn_5101" target="expand_5101" onclick="hideFunction("expand_5101")">Expand</button>
|
|
||||||
truly optional. One vendor may choose to include the item because a
|
|
||||||
particular marketplace requires it or because the vendor feels that
|
|
||||||
it enhances the product while another vendor may omit the same item.
|
|
||||||
An implementation which does not include a particular option MUST be
|
|
||||||
prepared to interoperate with another implementation which does
|
|
||||||
include the option, though perhaps with reduced functionality. In the
|
|
||||||
same vein an implementation which does include a particular option
|
|
||||||
MUST be prepared to interoperate with another implementation which
|
|
||||||
does not include the option (except, of course, for the feature the
|
|
||||||
option provides).</span>
|
|
||||||
<div class="nodeCloseClass" id="expand_5101"><div class="Verified-endnote-styling" id="eid5101">
|
|
||||||
<pre><b><i><a href="https://www.rfc-editor.org/errata/eid5101">EID 5101</a> (Verified) is as follows:</i></b>
|
|
||||||
|
|
||||||
<b>Section:</b> 5
|
|
||||||
|
|
||||||
<b>Original Text:</b>
|
|
||||||
|
|
||||||
5. MAY This word, or the adjective "OPTIONAL", mean that an item is
|
|
||||||
truly optional. One vendor may choose to include the item because a
|
|
||||||
particular marketplace requires it or because the vendor feels that
|
|
||||||
it enhances the product while another vendor may omit the same item.
|
|
||||||
An implementation which does not include a particular option MUST be
|
|
||||||
prepared to interoperate with another implementation which does
|
|
||||||
include the option, though perhaps with reduced functionality. In the
|
|
||||||
same vein an implementation which does include a particular option
|
|
||||||
MUST be prepared to interoperate with another implementation which
|
|
||||||
does not include the option (except, of course, for the feature the
|
|
||||||
option provides.)
|
|
||||||
|
|
||||||
<b>Corrected Text:</b>
|
|
||||||
|
|
||||||
5. MAY This word, or the adjective "OPTIONAL", mean that an item is
|
|
||||||
truly optional. One vendor may choose to include the item because a
|
|
||||||
particular marketplace requires it or because the vendor feels that
|
|
||||||
it enhances the product while another vendor may omit the same item.
|
|
||||||
An implementation which does not include a particular option MUST be
|
|
||||||
prepared to interoperate with another implementation which does
|
|
||||||
include the option, though perhaps with reduced functionality. In the
|
|
||||||
same vein an implementation which does include a particular option
|
|
||||||
MUST be prepared to interoperate with another implementation which
|
|
||||||
does not include the option (except, of course, for the feature the
|
|
||||||
option provides).
|
|
||||||
</pre>
|
|
||||||
<b>Notes:</b><br>
|
|
||||||
Full stop should appear outside the parentheses in the last sentence.
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
6. Guidance in the use of these Imperatives
|
|
||||||
|
|
||||||
Imperatives of the type defined in this memo must be used with care
|
|
||||||
and sparingly. In particular, they MUST only be used where it is
|
|
||||||
actually required for interoperation or to limit behavior which has
|
|
||||||
potential for causing harm <span class="Verified-inline-styling" id="inline-494">(e.g., limiting retransmissions)</span> For <button id="btn_494" target="expand_494" onclick="hideFunction("expand_494")">Expand Multiple</button>
|
|
||||||
<div class="nodeCloseClass" id="expand_494"><div class="Verified-endnote-styling" id="eid494">
|
|
||||||
<pre><b><i><a href="https://www.rfc-editor.org/errata/eid494">EID 494</a> (Verified) is as follows:</i></b>
|
|
||||||
|
|
||||||
<b>Section:</b> 6
|
|
||||||
|
|
||||||
<b>Original Text:</b>
|
|
||||||
|
|
||||||
(e.g., limiting retransmisssions)
|
|
||||||
|
|
||||||
<b>Corrected Text:</b>
|
|
||||||
|
|
||||||
(e.g., limiting retransmissions)
|
|
||||||
</pre>
|
|
||||||
<b>Notes:</b><br>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<div class="Verified-endnote-styling" id="eid496">
|
|
||||||
<pre><b><i><a href="https://www.rfc-editor.org/errata/eid496">EID 496</a> (Verified) is as follows:</i></b>
|
|
||||||
|
|
||||||
<b>Section:</b> 6
|
|
||||||
|
|
||||||
<b>Original Text:</b>
|
|
||||||
|
|
||||||
In particular, they MUST only be used where it is actually required
|
|
||||||
for interoperation or to limit behavior which has potential for
|
|
||||||
causing harm (e.g., limiting retransmisssions) For example, they
|
|
||||||
must not be used to try to impose a particular method on
|
|
||||||
implementors where the method is not required for interoperability.
|
|
||||||
|
|
||||||
<b>Corrected Text:</b>
|
|
||||||
|
|
||||||
In particular, they MUST only be used where it is actually required
|
|
||||||
for interoperation or to limit behavior which has potential for
|
|
||||||
causing harm (e.g., limiting retransmissions). For example, they
|
|
||||||
must not be used to try to impose a particular method on
|
|
||||||
implementors where the method is not required for interoperability.
|
|
||||||
</pre>
|
|
||||||
<b>Notes:</b><br>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div> example, they must not be used to try to impose a particular method
|
|
||||||
on implementors where the method is not required for
|
|
||||||
interoperability.
|
|
||||||
|
|
||||||
7. Security Considerations
|
|
||||||
|
|
||||||
These terms are frequently used to specify behavior with security
|
|
||||||
implications. The effects on security of not implementing a MUST or
|
|
||||||
SHOULD, or doing something the specification says MUST NOT or SHOULD
|
|
||||||
NOT be done may be very subtle. Document authors should take the time
|
|
||||||
to elaborate the security implications of not following
|
|
||||||
recommendations or requirements as most implementors will not have
|
|
||||||
had the benefit of the experience and discussion that produced the
|
|
||||||
specification.
|
|
||||||
|
|
||||||
8. Acknowledgments
|
|
||||||
|
|
||||||
The definitions of these terms are an amalgam of definitions taken
|
|
||||||
from a number of RFCs. In addition, suggestions have been
|
|
||||||
incorporated from a number of people including Robert Ullmann, Thomas
|
|
||||||
Narten, Neal McBurnett, and Robert Elz.
|
|
||||||
|
|
||||||
9. Author's Address
|
|
||||||
|
|
||||||
Scott Bradner
|
|
||||||
Harvard University
|
|
||||||
1350 Mass. Ave.
|
|
||||||
Cambridge, MA 02138
|
|
||||||
|
|
||||||
phone - +1 617 495 3864
|
|
||||||
|
|
||||||
email - sob@harvard.edu
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</pre></body></html>
|
|
||||||
BIN
www/root.png
Normal file
BIN
www/root.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 446 KiB |
Reference in New Issue
Block a user