mirror of https://github.com/bsnes-emu/bsnes.git
Update to v095 release.
byuu says: After 20 months of development, higan v095 is released at long last! The most notable feature is vastly improved Game Boy Advance emulation. With many thanks to endrift, Cydrak, Jonas Quinn and jchadwick, this release contains substantially improved CPU timings and many bugfixes. Being one of only two GBA emulators to offer ROM prefetch emulation, higan is very near mGBA in terms of accuracy, and far ahead of all others. As a result of these fixes, compatibility is also much higher than in v094. There are also several improvements to SNES emulation. Most significantly is support for mid-scanline changes to the background mode in the accuracy profile. Due to substantial changes to the user interface library used by higan, this release features yet again a brand-new UI. With the exception of video shaders and NSS DIP switch selection, it is at feature-parity with the previous UI. It also offers some new features that v094 lacked. The cheat code database has also been updated to the latest version by mightymo.
This commit is contained in:
parent
b113ecb5a3
commit
b0e862613b
1482
data/cheats.bml
1482
data/cheats.bml
File diff suppressed because it is too large
Load Diff
|
@ -8,7 +8,7 @@ using namespace nall;
|
||||||
|
|
||||||
namespace Emulator {
|
namespace Emulator {
|
||||||
static const string Name = "higan";
|
static const string Name = "higan";
|
||||||
static const string Version = "094.44";
|
static const string Version = "095";
|
||||||
static const string Author = "byuu";
|
static const string Author = "byuu";
|
||||||
static const string License = "GPLv3";
|
static const string License = "GPLv3";
|
||||||
static const string Website = "http://byuu.org/";
|
static const string Website = "http://byuu.org/";
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
include ../nall/GNUmakefile
|
include ../nall/GNUmakefile
|
||||||
include ../hiro/GNUmakefile
|
include ../hiro/GNUmakefile
|
||||||
|
|
||||||
flags += -O3 -I..
|
flags += -I.. -O3
|
||||||
link +=
|
link +=
|
||||||
objects := obj/hiro.o obj/icarus.o
|
objects := obj/hiro.o obj/icarus.o
|
||||||
objects += $(if $(call streq,$(platform),windows),obj/resource.o)
|
objects += $(if $(call streq,$(platform),windows),obj/resource.o)
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
#ifndef NALL_ENCODE_URL_HPP
|
||||||
|
#define NALL_ENCODE_URL_HPP
|
||||||
|
|
||||||
|
namespace nall { namespace Encode {
|
||||||
|
|
||||||
|
inline auto URL(const string& input) -> string {
|
||||||
|
string output;
|
||||||
|
for(auto c : input) {
|
||||||
|
if(c >= 'A' && c <= 'Z') { output.append(c); continue; }
|
||||||
|
if(c >= 'a' && c <= 'z') { output.append(c); continue; }
|
||||||
|
if(c >= '0' && c <= '9') { output.append(c); continue; }
|
||||||
|
if(c == '-' || c == '_' || c == '.' || c == '~') { output.append(c); continue; }
|
||||||
|
if(c == ' ') { output.append('+'); continue; }
|
||||||
|
unsigned hi = (c >> 4) & 15;
|
||||||
|
unsigned lo = (c >> 0) & 15;
|
||||||
|
output.append('%');
|
||||||
|
output.append((char)(hi < 10 ? ('0' + hi) : ('a' + hi - 10)));
|
||||||
|
output.append((char)(lo < 10 ? ('0' + lo) : ('a' + lo - 10)));
|
||||||
|
}
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
}}
|
||||||
|
|
||||||
|
#endif
|
|
@ -91,19 +91,11 @@ struct file : file_system_object, varint {
|
||||||
}
|
}
|
||||||
|
|
||||||
static auto write(const string& filename, const string& text) -> bool {
|
static auto write(const string& filename, const string& text) -> bool {
|
||||||
file fp;
|
return write(filename, (const uint8_t*)text.data(), text.size());
|
||||||
if(fp.open(filename, mode::write) == false) return false;
|
|
||||||
fp.print(text);
|
|
||||||
fp.close();
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static auto write(const string& filename, const vector<uint8_t>& buffer) -> bool {
|
static auto write(const string& filename, const vector<uint8_t>& buffer) -> bool {
|
||||||
file fp;
|
return write(filename, buffer.data(), buffer.size());
|
||||||
if(fp.open(filename, mode::write) == false) return false;
|
|
||||||
fp.write(buffer.data(), buffer.size());
|
|
||||||
fp.close();
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static auto write(const string& filename, const uint8_t* data, unsigned size) -> bool {
|
static auto write(const string& filename, const uint8_t* data, unsigned size) -> bool {
|
||||||
|
|
|
@ -11,47 +11,75 @@ struct Variable {
|
||||||
string value;
|
string value;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Variables : vector<Variable> {
|
struct SharedVariable {
|
||||||
auto append(const string& name, const string& value) -> void;
|
SharedVariable(const string& name = "", const string& value = "") : shared(new Variable{name, value}) {}
|
||||||
auto get(const string& name) const -> string;
|
|
||||||
auto remove(const string& name) -> void;
|
explicit operator bool() const { return (bool)shared->name; }
|
||||||
auto set(const string& name, const string& value) -> void;
|
auto operator()() const { return shared->value; }
|
||||||
|
auto& operator=(const string& value) { shared->value = value; return *this; }
|
||||||
|
|
||||||
|
auto name() const { return shared->name; }
|
||||||
|
auto value() const { return shared->value; }
|
||||||
|
|
||||||
|
auto& setName(const string& name) { shared->name = name; return *this; }
|
||||||
|
auto& setValue(const string& value = "") { shared->value = value; return *this; }
|
||||||
|
|
||||||
|
shared_pointer<Variable> shared;
|
||||||
};
|
};
|
||||||
|
|
||||||
auto Variables::append(const string& name, const string& value) -> void {
|
struct Variables {
|
||||||
vector::append({name, value});
|
auto operator[](const string& name) const -> SharedVariable {
|
||||||
}
|
for(auto& variable : variables) {
|
||||||
|
if(variable.shared->name.iequals(name)) return variable;
|
||||||
auto Variables::get(const string& name) const -> string {
|
|
||||||
for(auto& variable : *this) {
|
|
||||||
if(variable.name.iequals(name)) return variable.value;
|
|
||||||
}
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
auto Variables::remove(const string& name) -> void {
|
|
||||||
while(true) {
|
|
||||||
unsigned n = 0;
|
|
||||||
bool found = false;
|
|
||||||
for(auto& variable : *this) {
|
|
||||||
if(!variable.name.iequals(name)) { n++; continue; }
|
|
||||||
vector::remove(n);
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
if(found == false) break;
|
return {};
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
auto Variables::set(const string& name, const string& value) -> void {
|
auto operator()(const string& name) -> SharedVariable {
|
||||||
for(auto& variable : *this) {
|
for(auto& variable : variables) {
|
||||||
if(!variable.name.iequals(name)) continue;
|
if(variable.shared->name.iequals(name)) return variable;
|
||||||
variable.name = name;
|
}
|
||||||
variable.value = value;
|
return append(name);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
vector::append({name, value});
|
|
||||||
}
|
auto find(const string& name) const -> vector<SharedVariable> {
|
||||||
|
vector<SharedVariable> result;
|
||||||
|
for(auto& variable : variables) {
|
||||||
|
if(variable.shared->name.iequals(name)) result.append(variable);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto assign(const string& name, const string& value = "") -> SharedVariable {
|
||||||
|
for(auto& variable : variables) {
|
||||||
|
if(variable.shared->name.iequals(name)) {
|
||||||
|
variable.shared->value = value;
|
||||||
|
return variable;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return append(name, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto append(const string& name, const string& value = "") -> SharedVariable {
|
||||||
|
SharedVariable variable{name, value};
|
||||||
|
variables.append(variable);
|
||||||
|
return variable;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto remove(const string& name) -> void {
|
||||||
|
for(auto n : rrange(variables)) {
|
||||||
|
if(variables[n].shared->name.iequals(name)) variables.remove(n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto size() const { return variables.size(); }
|
||||||
|
auto begin() const { return variables.begin(); }
|
||||||
|
auto end() const { return variables.end(); }
|
||||||
|
auto begin() { return variables.begin(); }
|
||||||
|
auto end() { return variables.end(); }
|
||||||
|
|
||||||
|
vector<SharedVariable> variables;
|
||||||
|
};
|
||||||
|
|
||||||
struct Message {
|
struct Message {
|
||||||
using type = Message;
|
using type = Message;
|
||||||
|
@ -62,14 +90,11 @@ struct Message {
|
||||||
virtual auto body(const function<bool (const uint8_t* data, unsigned size)>& callback) const -> bool = 0;
|
virtual auto body(const function<bool (const uint8_t* data, unsigned size)>& callback) const -> bool = 0;
|
||||||
virtual auto setBody() -> bool = 0;
|
virtual auto setBody() -> bool = 0;
|
||||||
|
|
||||||
virtual auto header(const string& name) const -> string { return _header.get(name); }
|
Variables header;
|
||||||
virtual auto appendHeader(const string& name, const string& value = "") -> type& { return _header.append(name, value), *this; }
|
|
||||||
virtual auto removeHeader(const string& name) -> type& { return _header.remove(name), *this; }
|
|
||||||
virtual auto setHeader(const string& name, const string& value = "") -> type& { return _header.set(name, value), *this; }
|
|
||||||
|
|
||||||
|
//private:
|
||||||
string _head;
|
string _head;
|
||||||
string _body;
|
string _body;
|
||||||
Variables _header;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}}
|
}}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
#ifndef NALL_HTTP_REQUEST_HPP
|
#ifndef NALL_HTTP_REQUEST_HPP
|
||||||
#define NALL_HTTP_REQUEST_HPP
|
#define NALL_HTTP_REQUEST_HPP
|
||||||
|
|
||||||
|
#include <nall/decode/url.hpp>
|
||||||
|
#include <nall/encode/url.hpp>
|
||||||
#include <nall/http/message.hpp>
|
#include <nall/http/message.hpp>
|
||||||
|
|
||||||
namespace nall { namespace HTTP {
|
namespace nall { namespace HTTP {
|
||||||
|
@ -12,11 +14,11 @@ struct Request : Message {
|
||||||
|
|
||||||
explicit operator bool() const { return requestType() != RequestType::None; }
|
explicit operator bool() const { return requestType() != RequestType::None; }
|
||||||
|
|
||||||
inline auto head(const function<bool (const uint8_t* data, unsigned size)>& callback) const -> bool;
|
inline auto head(const function<bool (const uint8_t* data, unsigned size)>& callback) const -> bool override;
|
||||||
inline auto setHead() -> bool;
|
inline auto setHead() -> bool override;
|
||||||
|
|
||||||
inline auto body(const function<bool (const uint8_t* data, unsigned size)>& callback) const -> bool;
|
inline auto body(const function<bool (const uint8_t* data, unsigned size)>& callback) const -> bool override;
|
||||||
inline auto setBody() -> bool;
|
inline auto setBody() -> bool override;
|
||||||
|
|
||||||
auto ipv4() const -> bool { return _ipv6 == false; }
|
auto ipv4() const -> bool { return _ipv6 == false; }
|
||||||
auto ipv6() const -> bool { return _ipv6 == true; }
|
auto ipv6() const -> bool { return _ipv6 == true; }
|
||||||
|
@ -28,27 +30,15 @@ struct Request : Message {
|
||||||
auto path() const -> string { return _path; }
|
auto path() const -> string { return _path; }
|
||||||
auto setPath(const string& value) -> void { _path = value; }
|
auto setPath(const string& value) -> void { _path = value; }
|
||||||
|
|
||||||
auto appendHeader(const string& name, const string& value = "") -> type& { return Message::appendHeader(name, value), *this; }
|
Variables cookie;
|
||||||
auto removeHeader(const string& name) -> type& { return Message::removeHeader(name), *this; }
|
Variables get;
|
||||||
auto setHeader(const string& name, const string& value = "") -> type& { return Message::setHeader(name, value), *this; }
|
Variables post;
|
||||||
|
|
||||||
auto cookie(const string& name) const -> string { return _cookie.get(name); }
|
|
||||||
auto setCookie(const string& name, const string& value = "") -> void { _cookie.set(name, value); }
|
|
||||||
|
|
||||||
auto get(const string& name) const -> string { return _get.get(name); }
|
|
||||||
auto setGet(const string& name, const string& value = "") -> void { _get.set(name, value); }
|
|
||||||
|
|
||||||
auto post(const string& name) const -> string { return _post.get(name); }
|
|
||||||
auto setPost(const string& name, const string& value = "") -> void { _post.set(name, value); }
|
|
||||||
|
|
||||||
//private:
|
//private:
|
||||||
bool _ipv6 = false;
|
bool _ipv6 = false;
|
||||||
string _ip;
|
string _ip;
|
||||||
RequestType _requestType = RequestType::None;
|
RequestType _requestType = RequestType::None;
|
||||||
string _path;
|
string _path;
|
||||||
Variables _cookie;
|
|
||||||
Variables _get;
|
|
||||||
Variables _post;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
auto Request::head(const function<bool (const uint8_t*, unsigned)>& callback) const -> bool {
|
auto Request::head(const function<bool (const uint8_t*, unsigned)>& callback) const -> bool {
|
||||||
|
@ -56,10 +46,10 @@ auto Request::head(const function<bool (const uint8_t*, unsigned)>& callback) co
|
||||||
string output;
|
string output;
|
||||||
|
|
||||||
string request = path();
|
string request = path();
|
||||||
if(_get.size()) {
|
if(get.size()) {
|
||||||
request.append("?");
|
request.append("?");
|
||||||
for(auto& get : _get) {
|
for(auto& variable : get) {
|
||||||
request.append(get.name, "=", get.value, "&");
|
request.append(Encode::URL(variable.name()), "=", Encode::URL(variable.value()), "&");
|
||||||
}
|
}
|
||||||
request.rtrim("&", 1L);
|
request.rtrim("&", 1L);
|
||||||
}
|
}
|
||||||
|
@ -71,8 +61,8 @@ auto Request::head(const function<bool (const uint8_t*, unsigned)>& callback) co
|
||||||
default: return false;
|
default: return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(auto& header : _header) {
|
for(auto& variable : header) {
|
||||||
output.append(header.name, ": ", header.value, "\r\n");
|
output.append(variable.name(), ": ", variable.value(), "\r\n");
|
||||||
}
|
}
|
||||||
output.append("\r\n");
|
output.append("\r\n");
|
||||||
|
|
||||||
|
@ -81,7 +71,7 @@ auto Request::head(const function<bool (const uint8_t*, unsigned)>& callback) co
|
||||||
|
|
||||||
auto Request::setHead() -> bool {
|
auto Request::setHead() -> bool {
|
||||||
lstring headers = _head.split("\n");
|
lstring headers = _head.split("\n");
|
||||||
string request = headers.takeFirst().rtrim("\r");
|
string request = headers.takeFirst().rtrim("\r", 1L);
|
||||||
string requestHost;
|
string requestHost;
|
||||||
|
|
||||||
if(request.iendsWith(" HTTP/1.0")) request.irtrim(" HTTP/1.0", 1L);
|
if(request.iendsWith(" HTTP/1.0")) request.irtrim(" HTTP/1.0", 1L);
|
||||||
|
@ -106,8 +96,10 @@ auto Request::setHead() -> bool {
|
||||||
|
|
||||||
if(auto queryString = components(1)) {
|
if(auto queryString = components(1)) {
|
||||||
for(auto& block : queryString.split("&")) {
|
for(auto& block : queryString.split("&")) {
|
||||||
lstring variable = block.split("=", 1L);
|
auto p = block.split("=", 1L);
|
||||||
if(variable(0)) setGet(variable(0), variable(1));
|
auto name = Decode::URL(p(0));
|
||||||
|
auto value = Decode::URL(p(1));
|
||||||
|
if(name) get.append(name, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,18 +107,19 @@ auto Request::setHead() -> bool {
|
||||||
if(header.beginsWith(" ") || header.beginsWith("\t")) continue;
|
if(header.beginsWith(" ") || header.beginsWith("\t")) continue;
|
||||||
auto part = header.split(":", 1L).strip();
|
auto part = header.split(":", 1L).strip();
|
||||||
if(!part[0] || part.size() != 2) continue;
|
if(!part[0] || part.size() != 2) continue;
|
||||||
appendHeader(part[0], part[1]);
|
this->header.append(part[0], part[1]);
|
||||||
|
|
||||||
if(part[0].iequals("Cookie")) {
|
if(part[0].iequals("Cookie")) {
|
||||||
for(auto& block : part[1].split(";")) {
|
for(auto& block : part[1].split(";")) {
|
||||||
lstring variable = block.split("=", 1L).strip();
|
auto p = block.split("=", 1L).strip();
|
||||||
variable(1).trim("\"", "\"");
|
auto name = p(0);
|
||||||
if(variable(0)) setCookie(variable(0), variable(1));
|
auto value = p(1).trim("\"", "\"", 1L);
|
||||||
|
if(name) cookie.append(name, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(requestHost) setHeader("Host", requestHost); //request URI overrides host header
|
if(requestHost) header.assign("Host", requestHost); //request URI overrides host header
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -142,10 +135,46 @@ auto Request::body(const function<bool (const uint8_t*, unsigned)>& callback) co
|
||||||
|
|
||||||
auto Request::setBody() -> bool {
|
auto Request::setBody() -> bool {
|
||||||
if(requestType() == RequestType::Post) {
|
if(requestType() == RequestType::Post) {
|
||||||
if(header("Content-Type").iequals("application/x-www-form-urlencoded")) {
|
auto contentType = header["Content-Type"].value();
|
||||||
|
if(contentType.iequals("application/x-www-form-urlencoded")) {
|
||||||
for(auto& block : _body.split("&")) {
|
for(auto& block : _body.split("&")) {
|
||||||
lstring variable = block.rtrim("\r").split("=", 1L);
|
auto p = block.rtrim("\r").split("=", 1L);
|
||||||
if(variable(0)) setPost(variable(0), variable(1));
|
auto name = Decode::URL(p(0));
|
||||||
|
auto value = Decode::URL(p(1));
|
||||||
|
if(name) post.append(name, value);
|
||||||
|
}
|
||||||
|
} else if(contentType.imatch("multipart/form-data; boundary=?*")) {
|
||||||
|
auto boundary = contentType.iltrim("multipart/form-data; boundary=", 1L).trim("\"", "\"", 1L);
|
||||||
|
auto blocks = _body.split({"--", boundary}, 1024L); //limit blocks to prevent memory exhaustion
|
||||||
|
for(auto& block : blocks) block.trim("\r\n", "\r\n", 1L);
|
||||||
|
if(blocks.size() < 2 || (blocks.takeFirst(), !blocks.takeLast().beginsWith("--"))) return false;
|
||||||
|
for(auto& block : blocks) {
|
||||||
|
string name;
|
||||||
|
string filename;
|
||||||
|
string contentType;
|
||||||
|
|
||||||
|
auto segments = block.split("\r\n\r\n", 1L);
|
||||||
|
for(auto& segment : segments(0).split("\r\n")) {
|
||||||
|
auto statement = segment.split(":", 1L);
|
||||||
|
if(statement(0).ibeginsWith("Content-Disposition")) {
|
||||||
|
for(auto& component : statement(1).split(";")) {
|
||||||
|
auto part = component.split("=", 1L).strip();
|
||||||
|
if(part(0).iequals("name")) {
|
||||||
|
name = part(1).trim("\"", "\"", 1L);
|
||||||
|
} else if(part(0).iequals("filename")) {
|
||||||
|
filename = part(1).trim("\"", "\"", 1L);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if(statement(0).ibeginsWith("Content-Type")) {
|
||||||
|
contentType = statement(1).strip();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(name) {
|
||||||
|
post.append(name, segments(1));
|
||||||
|
post.append({name, ".filename"}, filename);
|
||||||
|
post.append({name, ".content-type"}, contentType);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,11 +14,11 @@ struct Response : Message {
|
||||||
explicit operator bool() const { return responseType() != 0; }
|
explicit operator bool() const { return responseType() != 0; }
|
||||||
auto operator()(unsigned responseType) -> type& { return setResponseType(responseType); }
|
auto operator()(unsigned responseType) -> type& { return setResponseType(responseType); }
|
||||||
|
|
||||||
inline auto head(const function<bool (const uint8_t* data, unsigned size)>& callback) const -> bool;
|
inline auto head(const function<bool (const uint8_t* data, unsigned size)>& callback) const -> bool override;
|
||||||
inline auto setHead() -> bool;
|
inline auto setHead() -> bool override;
|
||||||
|
|
||||||
inline auto body(const function<bool (const uint8_t* data, unsigned size)>& callback) const -> bool;
|
inline auto body(const function<bool (const uint8_t* data, unsigned size)>& callback) const -> bool override;
|
||||||
inline auto setBody() -> bool;
|
inline auto setBody() -> bool override;
|
||||||
|
|
||||||
auto request() const -> const Request* { return _request; }
|
auto request() const -> const Request* { return _request; }
|
||||||
auto setRequest(const Request& value) -> type& { _request = &value; return *this; }
|
auto setRequest(const Request& value) -> type& { _request = &value; return *this; }
|
||||||
|
@ -26,10 +26,6 @@ struct Response : Message {
|
||||||
auto responseType() const -> unsigned { return _responseType; }
|
auto responseType() const -> unsigned { return _responseType; }
|
||||||
auto setResponseType(unsigned value) -> type& { _responseType = value; return *this; }
|
auto setResponseType(unsigned value) -> type& { _responseType = value; return *this; }
|
||||||
|
|
||||||
auto appendHeader(const string& name, const string& value = "") -> type& { return Message::appendHeader(name, value), *this; }
|
|
||||||
auto removeHeader(const string& name) -> type& { return Message::removeHeader(name), *this; }
|
|
||||||
auto setHeader(const string& name, const string& value = "") -> type& { return Message::setHeader(name, value), *this; }
|
|
||||||
|
|
||||||
auto hasData() const -> bool { return (bool)_data; }
|
auto hasData() const -> bool { return (bool)_data; }
|
||||||
auto data() const -> const vector<uint8_t>& { return _data; }
|
auto data() const -> const vector<uint8_t>& { return _data; }
|
||||||
inline auto setData(const vector<uint8_t>& value) -> type&;
|
inline auto setData(const vector<uint8_t>& value) -> type&;
|
||||||
|
@ -61,8 +57,8 @@ auto Response::head(const function<bool (const uint8_t*, unsigned)>& callback) c
|
||||||
string output;
|
string output;
|
||||||
|
|
||||||
if(auto request = this->request()) {
|
if(auto request = this->request()) {
|
||||||
if(auto eTag = header("ETag")) {
|
if(auto eTag = header["ETag"]) {
|
||||||
if(eTag == request->header("If-None-Match")) {
|
if(eTag.value() == request->header["If-None-Match"].value()) {
|
||||||
output.append("HTTP/1.1 304 Not Modified\r\n");
|
output.append("HTTP/1.1 304 Not Modified\r\n");
|
||||||
output.append("Connection: close\r\n");
|
output.append("Connection: close\r\n");
|
||||||
output.append("\r\n");
|
output.append("\r\n");
|
||||||
|
@ -72,18 +68,18 @@ auto Response::head(const function<bool (const uint8_t*, unsigned)>& callback) c
|
||||||
}
|
}
|
||||||
|
|
||||||
output.append("HTTP/1.1 ", findResponseType(), "\r\n");
|
output.append("HTTP/1.1 ", findResponseType(), "\r\n");
|
||||||
for(auto& header : _header) {
|
for(auto& variable : header) {
|
||||||
output.append(header.name, ": ", header.value, "\r\n");
|
output.append(variable.name(), ": ", variable.value(), "\r\n");
|
||||||
}
|
}
|
||||||
if(hasBody()) {
|
if(hasBody()) {
|
||||||
if(!header("Content-Length") && !header("Transfer-Encoding").iequals("chunked")) {
|
if(!header["Content-Length"] && !header["Transfer-Encoding"].value().iequals("chunked")) {
|
||||||
output.append("Content-Length: ", findContentLength(), "\r\n");
|
output.append("Content-Length: ", findContentLength(), "\r\n");
|
||||||
}
|
}
|
||||||
if(!header("Content-Type")) {
|
if(!header["Content-Type"]) {
|
||||||
output.append("Content-Type: ", findContentType(), "\r\n");
|
output.append("Content-Type: ", findContentType(), "\r\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(!header("Connection")) {
|
if(!header["Connection"]) {
|
||||||
output.append("Connection: close\r\n");
|
output.append("Connection: close\r\n");
|
||||||
}
|
}
|
||||||
output.append("\r\n");
|
output.append("\r\n");
|
||||||
|
@ -105,7 +101,7 @@ auto Response::setHead() -> bool {
|
||||||
if(header.beginsWith(" ") || header.beginsWith("\t")) continue;
|
if(header.beginsWith(" ") || header.beginsWith("\t")) continue;
|
||||||
lstring variable = header.split(":", 1L).strip();
|
lstring variable = header.split(":", 1L).strip();
|
||||||
if(variable.size() != 2) continue;
|
if(variable.size() != 2) continue;
|
||||||
appendHeader(variable[0], variable[1]);
|
this->header.append(variable[0], variable[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -114,7 +110,7 @@ auto Response::setHead() -> bool {
|
||||||
auto Response::body(const function<bool (const uint8_t*, unsigned)>& callback) const -> bool {
|
auto Response::body(const function<bool (const uint8_t*, unsigned)>& callback) const -> bool {
|
||||||
if(!callback) return false;
|
if(!callback) return false;
|
||||||
if(!hasBody()) return true;
|
if(!hasBody()) return true;
|
||||||
bool chunked = header("Transfer-Encoding") == "chunked";
|
bool chunked = header["Transfer-Encoding"].value() == "chunked";
|
||||||
|
|
||||||
if(chunked) {
|
if(chunked) {
|
||||||
string prefix = {hex(findContentLength()), "\r\n"};
|
string prefix = {hex(findContentLength()), "\r\n"};
|
||||||
|
@ -160,7 +156,7 @@ auto Response::hasBody() const -> bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Response::findContentLength() const -> unsigned {
|
auto Response::findContentLength() const -> unsigned {
|
||||||
if(auto contentLength = header("Content-Length")) return decimal(contentLength);
|
if(auto contentLength = header["Content-Length"]) return contentLength.value().decimal();
|
||||||
if(_body) return _body.size();
|
if(_body) return _body.size();
|
||||||
if(hasData()) return data().size();
|
if(hasData()) return data().size();
|
||||||
if(hasFile()) return file::size(file());
|
if(hasFile()) return file::size(file());
|
||||||
|
@ -169,7 +165,7 @@ auto Response::findContentLength() const -> unsigned {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Response::findContentType() const -> string {
|
auto Response::findContentType() const -> string {
|
||||||
if(auto contentType = header("Content-Type")) return contentType;
|
if(auto contentType = header["Content-Type"]) return contentType.value();
|
||||||
if(hasData()) return "application/octet-stream";
|
if(hasData()) return "application/octet-stream";
|
||||||
if(hasFile()) return findContentType(suffixname(file()));
|
if(hasFile()) return findContentType(suffixname(file()));
|
||||||
return "text/html; charset=utf-8";
|
return "text/html; charset=utf-8";
|
||||||
|
@ -229,22 +225,22 @@ auto Response::findResponseType() const -> string {
|
||||||
|
|
||||||
auto Response::setData(const vector<uint8_t>& value) -> type& {
|
auto Response::setData(const vector<uint8_t>& value) -> type& {
|
||||||
_data = value;
|
_data = value;
|
||||||
setHeader("Content-Length", value.size());
|
header.assign("Content-Length", value.size());
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Response::setFile(const string& value) -> type& {
|
auto Response::setFile(const string& value) -> type& {
|
||||||
_file = value;
|
_file = value;
|
||||||
string eTag = {"\"", string::datetime(file::timestamp(value, file::time::modify)), "\""};
|
string eTag = {"\"", string::datetime(file::timestamp(value, file::time::modify)), "\""};
|
||||||
setHeader("Content-Length", file::size(value));
|
header.assign("Content-Length", file::size(value));
|
||||||
setHeader("Cache-Control", "public");
|
header.assign("Cache-Control", "public");
|
||||||
setHeader("ETag", eTag);
|
header.assign("ETag", eTag);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Response::setText(const string& value) -> type& {
|
auto Response::setText(const string& value) -> type& {
|
||||||
_text = value;
|
_text = value;
|
||||||
setHeader("Content-Length", value.size());
|
header.assign("Content-Length", value.size());
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,13 +11,13 @@ namespace nall { namespace HTTP {
|
||||||
|
|
||||||
struct Role {
|
struct Role {
|
||||||
struct Settings {
|
struct Settings {
|
||||||
signed connectionLimit = 1024; //server
|
signed connectionLimit = 1 * 1024; //server
|
||||||
signed headSizeLimit = 16384; //client, server
|
signed headSizeLimit = 16 * 1024; //client, server
|
||||||
signed bodySizeLimit = 65536; //client, server
|
signed bodySizeLimit = 8192 * 1024; //client, server
|
||||||
signed chunkSize = 32768; //client, server
|
signed chunkSize = 32 * 1024; //client, server
|
||||||
signed threadStackSize = 131072; //server
|
signed threadStackSize = 128 * 1024; //server
|
||||||
signed timeoutReceive = 15000; //server
|
signed timeoutReceive = 15 * 1000; //server
|
||||||
signed timeoutSend = 15000; //server
|
signed timeoutSend = 15 * 1000; //server
|
||||||
} settings;
|
} settings;
|
||||||
|
|
||||||
inline auto configure(const string& parameters) -> bool;
|
inline auto configure(const string& parameters) -> bool;
|
||||||
|
@ -82,8 +82,8 @@ auto Role::download(signed fd, Message& message) -> bool {
|
||||||
if(head.endsWith("\r\n\r\n") || head.endsWith("\n\n")) {
|
if(head.endsWith("\r\n\r\n") || head.endsWith("\n\n")) {
|
||||||
headReceived = true;
|
headReceived = true;
|
||||||
if(!message.setHead()) return false;
|
if(!message.setHead()) return false;
|
||||||
chunked = message.header("Transfer-Encoding").iequals("chunked");
|
chunked = message.header["Transfer-Encoding"].value().iequals("chunked");
|
||||||
contentLength = decimal(message.header("Content-Length"));
|
contentLength = message.header["Content-Length"].value().decimal();
|
||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -60,6 +60,7 @@
|
||||||
#include <nall/decode/url.hpp>
|
#include <nall/decode/url.hpp>
|
||||||
#include <nall/decode/zip.hpp>
|
#include <nall/decode/zip.hpp>
|
||||||
#include <nall/encode/base64.hpp>
|
#include <nall/encode/base64.hpp>
|
||||||
|
#include <nall/encode/url.hpp>
|
||||||
#include <nall/hash/crc16.hpp>
|
#include <nall/hash/crc16.hpp>
|
||||||
#include <nall/hash/crc32.hpp>
|
#include <nall/hash/crc32.hpp>
|
||||||
#include <nall/hash/sha256.hpp>
|
#include <nall/hash/sha256.hpp>
|
||||||
|
|
|
@ -166,7 +166,7 @@ InputManager::InputManager() {
|
||||||
inputMapping->link = &input;
|
inputMapping->link = &input;
|
||||||
input.guid = (uintptr_t)inputMapping;
|
input.guid = (uintptr_t)inputMapping;
|
||||||
|
|
||||||
nodeDevice.append(inputMapping->assignment, inputMapping->name);
|
nodeDevice.append(inputMapping->assignment, string{inputMapping->name}.replace(" ", ""));
|
||||||
}
|
}
|
||||||
|
|
||||||
nodePort.append(nodeDevice, string{inputDevice.name}.replace(" ", ""));
|
nodePort.append(nodeDevice, string{inputDevice.name}.replace(" ", ""));
|
||||||
|
|
Loading…
Reference in New Issue