Giter Site home page Giter Site logo

huntlabs / hunt-framework Goto Github PK

View Code? Open in Web Editor NEW
298.0 34.0 29.0 3.34 MB

A Web framework for D Programming Language. Full-stack high-performance.

Home Page: http://www.huntlabs.net

D 100.00%
web-framework full-stack restful-api http2 websocket dlang orm mvc template-engine microservice webservice

hunt-framework's Introduction

Build Status

Hunt framework

Hunt is a high-level D Programming Language Web framework that encourages rapid development and clean, pragmatic design. It lets you build high-performance Web applications quickly and easily. Framework

Requirements

  • Compiler: DMD <= 2.098.0 and >= 2.095.0

Getting Started

Create a project

git clone https://github.com/huntlabs/hunt-skeleton.git myproject
cd myproject
dub run -v

Open the URL with the browser:

http://localhost:8080/

Router config

config/routes

#
# [GET,POST,PUT...]    path    controller.action
#

GET     /               index.index
GET     /users          user.list
POST    /user/login     user.login
*       /images         staticDir:public/images

Add Controller

module app.controller.index;

import hunt.framework;

class IndexController : Controller
{
    mixin MakeController;

    @Action
    string index()
    {
        return "Hello world!";
    }
}

For more, see hunt-skeleton or hunt-examples.

Components

Basics

Security

Database

Frontend

Digging Deeper

Resources

Community

hunt-framework's People

Contributors

donglei avatar dushibaiyu avatar gaoxincheng avatar hanfengfg avatar heromyth avatar jiyahan avatar liuhongfei0826 avatar n8sh avatar nilufanier avatar noclear avatar shove70 avatar vegax87 avatar viile avatar wangyun0831 avatar zhangyuchun avatar zoujiaqing avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

hunt-framework's Issues

A render method string processing bug.

layout.dhtml:

<html>
    <body>
        <div class="content">
            {{ yield }}
        </div>
    </body>
<html>

content.dhtml:

<form action="/login" method="POST">
	<input type="text" name="username" /><br />
	<input type="password" name="password" /><br />
	<input type="submit" value="login" />
</form>

code:

this.view.setLayout!"layout.dhtml"();	
this.render!"content.dhtml"();

---------------- render result: ----------------

<html>
    <body>
        <div class="content">
            <form action="/login" method="POST">
	          <input type="text" name="username" /><br />
	          <input type="password" name="password" /><br />
	          <input type="submit" value="login" />
           </form                                   -- Missing a character ">"
        </div>
    </body>
<html>

dub update error

Package errors:

Version 0.7.0: Package description contains an obsolete "version" field and does not match tag 0.7.0: 0.7.0-beta6
Version 0.7.0-beta10: Package description contains an obsolete "version" field and does not match tag 0.7.0-beta10: 0.7.0-beta6

I want import rpc service to hunt framework

Add config options:

rpc.service.enabled=true
rpc.service.address=127.0.0.1
rpc.service.port=1234
rpc.service.workerThreads=4
rpc.service.password=123456

Add folder:

app/service/

Add class like:

class hunt.application.rpcservice.RpcService {}

Add some code to Application class:

final class Application
{
    // ...

    public void startRpcService()
    {
        import hunt.application.rpcservice;
        auto rpcService = new RpcService(/* rpc.service.address, rpc.service.port */);
        rpcService.setWorderThreads(4);
        rpcService.start();
    }

    // ...
}

The session ID is not safe

The problem

The way the session ID as generated is unsafe :

public string generateSessionId()
{
    import std.digest.sha;
    import std.format;
    import std.datetime;
    import std.random;
    import core.cpuid;
    import std.string;

    auto str = toHexString(sha1Of(format("%s--%s--%s",
        Clock.currTime().toISOExtString, uniform(long.min, long.max), processor())));

    return toLower(cast(string)(str[]));
}

This showcases many cryptographic issues:

  • the current time isn't random at all and is easy to predict with a low error margin.

  • uniform isn't a cryptographically secured pseudo random number generator, given enough data (a few hundreds of session ids, nothing difficult to generate) it's easy to predict any further input.

  • the processor is not random either, it's possible to find it and once leaked it is very hard to change

  • sha1 is completely unsafe and should never be used. There is no good reason to use it today instead of sha256, sha512 or blake2.

The solution

A session id should be unique and cryptographically secure. Unfortunately D
doesn't currently provide a standard CSPRNG. I would recommend to take the
sha256 of 64 bytes of your systems random number generator source :

  • /dev/urandom on Linux/MAC
  • CryptGenRandom on Windows

If your system doesn't provide one of those refuse to compile! It's important
not to silently induce a fake sense of security.

More english please!

Sorry, but could you use more English in comments and in the docs. I am interesting in hunt, but I do not know Chines.

Response.setCookie lacks a practical function

    /**
     * set Cookie
     */
    auto setCookie(string name, string value, int expires, string path = "/", string domain = null)
    {
        import std.typecons;
        auto cookie = scoped!Cookie(name, value, [
                "path": path,
                "domain": domain,
                "expires": printDate(cast(DateTime) Clock.currTime(UTC()) + dur!"seconds"(expires))
            ]);

        setHeader(HTTPHeaderCode.SET_COOKIE, cookie.output(""));

        return this;
    }

In actual use, we often need to use the browser session cycle of cookie, other frameworks usually do not need to set the “expires”.

Recommendation 1:

Add a setCookie overloaded method.

  /**
     * set Cookie
     */
    auto setCookie(string name, string value, string path = "/", string domain = null)
    {
        import std.typecons;
        auto cookie = scoped!Cookie(name, value, [
                "path": path,
                "domain": domain,
                "max-age" : "seconds"       // browser session
            ]);

        setHeader(HTTPHeaderCode.SET_COOKIE, cookie.output(""));

        return this;
    }

Recommendation 2:

The 0 value of parameter expires is used as a special value for this utility function.

    /**
     * set Cookie
     */
    auto setCookie(string name, string value, int expires = 0, string path = "/", string domain = null)
    {
        import std.typecons;
        auto cookie = scoped!Cookie(name, value, [
                "path": path,
                "domain": domain
            ]);

        if (expires != 0)
	        cookie.params["expirse"] = printDate(cast(DateTime) Clock.currTime(UTC()) + dur!"seconds"(expires));
	else
		cookie.params["max-age"] = "seconds";

        setHeader(HTTPHeaderCode.SET_COOKIE, cookie.output(""));

        return this;
    }

Rest API and Deploy into web server

I have create a sample web app using hunt framework. It is simple and easy to develop.
I have struggled with

How to create rest api(return json / xml based on the request)
How to deploy into web server (XAMPP, Apache)

问个数据库的问题

问一下,如果数据库改成mysql,是不是
database.default.driver=mysql
这么写就可以了?database.default.url格式照旧?

0.4.0 is not buildable

I mean: hunt/examples/website/

You did release too early, 0.4.0 is not even buildable:

....\source\hunt\view\package.d(93,28): Error: file "layouts/main.dhtml" cannot
be found or not in a path specified with -J
....\source\hunt\view\templerender.d(24,13): Error: template instance hunt.view
.compile_temple_file!("layouts/main.dhtml", void) error instantiating
source\app\controller\index.d(51,12): instantiated from here: setLayout!"
layouts/main.dhtml"
Compiling content.dhtml...
context parsing..............................................
delim check........................
dmd failed with exit code 1.

Please do release only after testing. Or people will think about Hunt how about low quality project.

add Memcache & Redis & Cache support?

I want use memcach / redis / cache.

config/application.conf

cache.storage = memory
cache.prefix = huntcache_
cache.expire = 3600

memcache.enabled = true
memcache.servers = 127.0.0.1:11211, 127.0.0.1:11212

redis.enabeld = true
redis.host = 127.0.0.1
redis.port = 6379
redis.database = 0
redis.password = ""
redis.timeout = 0

Global can use this code:

Cache.set("key", value);
string value = Cache.get("key");

Memcache.set("key", value, 3600);
string value = Memcache.get("key");

Redis.hSet("domain", "google", "www.google.cn");
string domain = Redis.hGet("domain", "google");

Please add a link from readme to the Wiki

Many projects don't have a Wiki, so that at first I missed it, when reading only the readme and installing your skeleton example.

And than please place a view into the skeleton, it is not mentioned where to store the view.
And translate the complete wiki to English :-)

Fail to dub run hunt-skeleton

git clone https://github.com/putaolabs/hunt-skeleton.git myproject

but fail to dub run the executable for two reasons:

  1. It needs logs directory, I can make it manually.
  2. I have change http.port = 8083 in config/application.conf, but it still remains 8080
g:\dev\d\myproject>dub run --force
Performing "debug" build using dmd for x86.
collie 0.9.2: building configuration "default"...
use CustomTimer!!!!
hunt 0.5.1: building configuration "default"...
use CustomTimer!!!!
context parsing..............................................
delim check........................
hunt-skeleton ~master: building configuration "application"...
use CustomTimer!!!!
Linking...
Running .\hunt-skeleton.exe
2017-02-10T14:45:15.187:C:\Users\Administrator\AppData\Roaming\dub\packages\hunt-0.5.1\hunt\source\h
unt\application\controller.d:addRouteList:211 addRouteList : app.controller.index.IndexController.in
dex

std.socket.SocketOSException@std\socket.d(2723): Unable to bind socket: 以一种访问权限不允许的方式做了一个访问套接字的尝试。
----------------
0x004CC050 in @trusted void std.socket.Socket.bind(std.socket.Address)
...
**Because 8080 has been occupied**

Error in template rendering

My development environment:
debian/jessie64 , dub 1.3.0 , hunt-0.7.1

If the declaration statement is placed on the first line, although the compilation can be passed, the rendering result is empty.

{% import hunt.i18n; %}
<html>
    <heade></head>
    ...

Cache methods?

I think:
void set(string key, string value);
void set!T(string key, T value);
string get(string key);
T get!T(string key);
void remove(string key);
void clear();
void setExpires(int expires);

What do you want?

Hunt vs Vibed

What is the design/philosophy difference between Hunt and Vibed?

Example website: std.stdio.setmode is not visible\accessible from module cgi

I use DMD 2.072.0 on Win 10

Performing "debug" build using dmd for x86.
collie 0.8.7: target for configuration "default" is up to date.
hunt 0.4.2+commit.7.gdc565da: building configuration "library"...
use CustomTimer!!!!
....\source\arsd\cgi.d(301,3): Deprecation: std.stdio.setmode is not visible from module cgi
....\source\arsd\cgi.d(301,10): Error: function std.stdio.setmode is not accessible from module cgi
context parsing..............................................
delim check........................
dmd failed with exit code 1.

When remove a cookie, there is a user experience problem.

remove a cookie:

response.setCookie("username", "", -1);

When the second parameter “value” is passed into a blank string “”, a assert error is encountered.
While removing the cookie need to pass a specific value, is unreasonable.

Recommendation

cookie.d line 361:

    void set(string name, string value)
    in
    {
        assert(name != null);
        //assert(value != null);      // Comment it, or: Comment on it, or: rewrite the assert statement based on the value of the expires variable
    }

Thanks for providing such a powerful Hunt.

There was a problem with the last submission.

There was a problem with the last submission:

session.d:
void setExpire(int expire)
{
this._expire = expire;
this._cacheDriver.setExpire(expire); <-- here
}

file.d: (class FileCache)

override void setExpire(int expire)
{
    this._expire = expire;		<-- here
}

Cause app.start() not run.

关于日志问题

问一下,日志的level,设置成info,但是没正常的访问日志输出啊?trace的输出,又非常详细,有很多调试信息。

Controller's Action can return string / int / JSONValue

import hunt;

class IndexController : Controller
{
	mixin MakeController;

	@Action
	string helloworld()
	{
		return "hello world!";
	}

	@Action
	int hello123()
	{
		return 123;
	}

	@Action
	JSONValue hellojson()
	{
		JSONValue j = [ "hello": "json" ];

		return j;
	}

	@Action
	Reponse hello()
	{
		response.setContent("hello");

		return response;
	}
}

Request.session() return Session object?

Hi Mr @Heromyth .

Now the session is not good.

I wanted:

// To store data in the session, you will typically use the put method.
request.session().set("key", "value");

// When you retrieve an item from the session, you may also pass a default value as the second argument to the get method.
string value = request.session().get("key", "default");

// If you would like to retrieve all the data in the session.
string[string] data = data = request.session().all();

// delete for key
request.session().forget("key");

// delete all data
request.session().flush();

// To determine if an item is present in the session, you may use the has method. 
if (request.session().has("username")) {
    //
}

// To determine if an item is present in the session, even if its value is null, you may use the exists method.
if (request.session().exists("username")) {
    //
}

SessionId persistence bug.

SessionInterface session = request.getSession();

When we use session, we get a different sessionId for each new request on the own client. Access to all the source code of hunt, found that: according to the designer's intent is to use the setCookie("hunt_session", sessionId) to save the sessionId, and the source code is not setCookie("hunt_session", ...) this code should be careful not to miss.

Solution

at line: 138, in request.d:

	SessionInterface getSession( S = Session)(string sessionName = "hunt_session", SessionStorageInterface t =  newStorage()) //if()
	{
		auto co = getCookie(sessionName);
		if (co is null) return new S(t);
		return new S(co.value, t);
	}

Replace this method as:

	SessionInterface getSession( S = Session)(string sessionName = "hunt_session", SessionStorageInterface t =  newStorage()) //if()
	{
		auto cookie = getCookie(sessionName);
		if (cookie is null)
		{
			S session = new S(t);
			string sessionId = session.getId();
			this.createResponse().setCookie(sessionName, sessionId);	// In fact, this sentence is added, the sessionId will be saved to the cookie
		
			return session;
		}
	
		return new S(cookie.value, t);
	}

about wwwroot.

http.path not work.
code:
this.staticRootRoute = this.makeRoute("GET", "/", "staticDir:wwwroot/", group);

建议添加isAsync To Controller

可以添加一个 bool isAsync() 函数到Controller类,默认是return true。
允许自己定义成return false。
如果return false。 就可以在handler处理完逻辑GC.free 掉 Controller。
以便优化GC暂停频率和时间。

Possible cache corruption

Hi,

The way the function getByKey in mapCache is implemented right know is not safe:

override string getByKey(string master_key,string key, lazy string v= string.init)
{
    string pk = master_key ~ key;
    _mutex.reader.lock();
    scope(exit) _mutex.reader.unlock();
    return _map.get(pk,v);
}

By just concatenating the keys it is possible to access other access other keys by mistake:

getByKey("AA", "B") == getByKey("A", "AB");

For example this can have security consequences if the key is taken from user input even without any access to the master key part.

Outside of any context the best way to concatenate them I can think of is:

override string getByKey(string master_key, string key, lazy string v=string.init)
{
    string prefix = master_key.length.to!string ~ ",";
    string pk = prefix ~ master_key ~ key;
    _mutex.reader.lock();
    scope(exit) _mutex.reader.unlock();
    return _map.get(pk,v);
}

It works by making the length of the master key explicit. I use a non-numerical separator to remove ambiguity in case the master_key starts with a number. Of course the setByKey function must be adapted too. That way it is not possible to be ambiguous :

getByKey("AA", "B") -> 2,AAB
getByKey("A", "AB") -> 1,AAB

Note that in most cases you don't have to unserialize that key, the setByKey just builds its key the same way, it doesn't have to check existing the formatting of existing keys.

hunt crashes

Hunt crashed When the content-type was “x-www-form-urlencoded” and the form was empty

about hunt framework config options

I want to adjust config options, what do you want?

application.name=MYSITE

application.baseUrl=http://localhost:8080/

application.defaultCookieDomain=.example.com

application.defaultLanguage=zh-CN

application.languages=zh-CN,en-US

application.secret=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

application.encoding=UTF-8

session.prefix=hunt

session.storage=memcache

session.expire=3600

http.address=127.0.0.1

http.port=8080

http.workerThreads=4

http.cacheControl=0

http.path=/data/www/example.com/htdocs/

https.enabled=true

https.protocol = "TLS";

https.keyStore=keystore.p12

https.keyStoreType=PKCS12

https.keyStorePassword=secret


log.level=DEBUG

log.path=data/logs/

log.file=huntframework.log


upload.path=data/attachments/

upload.maxSize=4096000


cron.noon=0 0 12 * * ?

date.format=yyyy-mm-dd

date.timeZone=Asia/Shanghai

database.default.driver=postgres

database.default.url=postgres://username:password@hostname:5432/dbname

database.default.pool.maxSize=60

database.default.pool.minSize=10

database.default.pool.timeout=10000

mail.smtp.host=smtp.gmail.com

mail.smtp.channel

mail.smtp.port=2500

mail.smtp.protocol=smtps

mail.smtp.user

mail.smtp.password

hunt 0.6.0 版本问题

使用hunt 0.6.0 版本结合 dub build 命令编译,出现如下问题

Warning for package libasync, configuration 32mscoff

The following compiler flags have been specified in the package description
file. They are handled by DUB and direct use in packages is discouraged.
Alternatively, you can set the DFLAGS environment variable to pass custom flags
to the compiler, or use one of the suggestions below:

-m32mscoff: Use --arch=x86/--arch=x86_64/--arch=x86_mscoff to specify the target architecture

Warning for package libasync, configuration 32mscoff

The following compiler flags have been specified in the package description
file. They are handled by DUB and direct use in packages is discouraged.
Alternatively, you can set the DFLAGS environment variable to pass custom flags
to the compiler, or use one of the suggestions below:

-m32mscoff: Use --arch=x86/--arch=x86_64/--arch=x86_mscoff to specify the target architecture

Performing "debug" build using dmd for x86_64.
collie 0.9.2: building configuration "default"...
derelict-util 2.0.6: building configuration "library"...
derelict-pq 2.0.3: building configuration "library"...
vibe-d:utils 0.7.30: building configuration "library"...
vibe-d:data 0.7.30: building configuration "library"...
vibe-d:core 0.7.30: building configuration "libevent"...
mysql-native 1.0.0: building configuration "library"...
ddbc 0.3.2: building configuration "full"...
../../../../.dub/packages/ddbc-0.3.2/ddbc/source/ddbc/drivers/mysqlddbc.d(319,15): Error: undefined identifier 'Command'
../../../../.dub/packages/ddbc-0.3.2/ddbc/source/ddbc/drivers/mysqlddbc.d(342,23): Error: undefined identifier 'FieldDescription'
../../../../.dub/packages/ddbc-0.3.2/ddbc/source/ddbc/drivers/mysqlddbc.d(359,23): Error: undefined identifier 'ParamDescription'
dmd failed with exit code 1

Have you thought about a scaffolding scirpt

For getting started with a certain db-table I like the rails scaffolding a lot.

I thought it would be quite cool to export an mysqldump of the table definition and read this
information to get the definitions needed for the ORM mapping.
Unfortunately my D skills are still very small, but in theory it should be possible to do this at
compiletime? Producing the needed string mixins.

If you could offer something like this I think Hunt would be far more attractive to give it a try.

Change route group support type

If the site domain is www.huntframework.com, add a config item to config/application.conf like this:

route.groups = admin:path:admincp, api:domain:api.huntframework.com

add to config files to admin & api:

touch config/admin.routes
touch config/api.routes

www.huntframework.com access to this Controllers dir:

source/app/controller/

www.huntframework.com/admincp/ access to this COntrollers dir:

source/app/controller/admin/

api.huntframework.com access to this controllers dir:

source/app/controller/api/

PS: this example for single module.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.