/
index.html
executable file
·280 lines (238 loc) · 15.7 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
<!DOCTYPE html>
<!--[if lt IE 7 ]><html class="ie ie6" lang="en"> <![endif]-->
<!--[if IE 7 ]><html class="ie ie7" lang="en"> <![endif]-->
<!--[if IE 8 ]><html class="ie ie8" lang="en"> <![endif]-->
<!--[if (gte IE 9)|!(IE)]><!--> <html lang="en"> <!--<![endif]-->
<head>
<!-- Basic Page Needs
================================================== -->
<meta charset="utf-8" />
<title>Klarna RnD-blog</title>
<meta name="description" content="">
<meta name="author" content="">
<!--[if lt IE 9]>
<script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<!-- Mobile Specific Metas
================================================== -->
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
<!-- CSS
================================================== -->
<link rel="stylesheet" href="stylesheets/base.css">
<link rel="stylesheet" href="stylesheets/skeleton.css">
<link rel="stylesheet/less" type="text/css" href="stylesheets/style.less">
<link rel="stylesheet" href="http://alexgorbatchev.com/pub/sh/current/styles/shCore.css" />
<link rel="stylesheet" href="http://alexgorbatchev.com/pub/sh/current/styles/shThemeRDark.css" />
<!-- Favicons
================================================== -->
<link rel="shortcut icon" href="images/favicon.ico">
<link rel="apple-touch-icon" href="images/apple-touch-icon.png">
<link rel="apple-touch-icon" sizes="72x72" href="images/apple-touch-icon-72x72.png" />
<link rel="apple-touch-icon" sizes="114x114" href="images/apple-touch-icon-114x114.png" />
</head>
<body>
<!-- Primary Page Layout
================================================== -->
<!-- Delete everything in this .container and get started on your own site! -->
<header>
<div class="container">
<h1>BLOG</h1>
</div><!--! container -->
</header>
<div class="mainarea">
<div class="container">
<div class="row post">
<div class="three columns metainfo alpha">
<p>By: <strong>Tobbe</strong> <br />
Mar 5, 2011</p>
</div><!--! end .metainfo -->
<div class="nine columns postcontent omega">
<h1>Using SimpleBridge</h1>
<p>I like SimpleBridge; written by Rusty and part of Nitrogen. I often use it as a separate component, i.e without using Nitrogen. SimpleBridge provides an abstraction above the underlying HTTP engine. Apart from being a nice programming model it also makes it very easy to replace that HTTP engine if you so should wish.</p>
<p>Usually I use SimpleBridge together with Yaws, together with one of my rebar templates. The setup, shown below, is dead easy:</p>
<pre class="brush: erlang">
start_link(yaws) ->
SL = [{appmods, [{"/", ?MODULE}]},
{port, bfp:port()},
{servername, bfp:servername()},
{listen, bfp:ip()}],
GL = [{logdir, bfp:log_dir()},
{cache_refresh_secs, 5}],
ok = yaws:start_embedded(bfp:docroot(), SL, GL, "bfp"),
{ok, whereis(yaws_sup)};
</pre>
<p>In the example above I hijack the URL space using an appmod. Every HTTP request to the system will end up with a call to the out/1 function and it is there the SimpleBridge magic happends:</p>
<pre class="brush: erlang">
out(Info) ->
RequestBridge = simple_bridge:make_request(yaws_request_bridge, Info),
ResponseBridge = simple_bridge:make_response(yaws_response_bridge, Info),
bfp:run(RequestBridge, ResponseBridge).
</pre>
<p>The rest of the code will only deal with the RequestBridge and ResponseBridge objects (which are two parameterized modules):</p>
<pre class="brush: erlang">
run(Request, Response0) ->
Method = Request:request_method(),
Path = Request:path(),
...snip...
Response:build_response().
</pre>
<p>Note how data is extracted from the HTTP engine. At the end a response is produced. The response is built up during the processing of the request. With a helper function it can look like this:</p>
<pre class="brush: erlang">
bfp:mk_response(Response, 200,
[{"Content-Type", "text/html"}],
Data);
where mk_response/4 is implemented as:
%% Create a SimpleBridge response
mk_response(Response, StatusCode, Headers, Data) ->
foldf([mk_status_code(StatusCode),
mk_headers(Headers),
mk_data(Data)],
Response).
mk_status_code(StatusCode) ->
fun(Response) -> Response:status_code(StatusCode) end.
mk_headers(Headers) ->
fun(Response) ->
lists:foldl(fun({H,V},R) -> R:header(H,V) end, Response, Headers)
end.
mk_data(Data) ->
fun(Response) -> Response:data(Data) end.
foldf(Fs,Db) ->
lists:foldl(fun(F,D) -> F(D) end, Db, Fs).
</pre>
<p>Now, before you run off to play with this, I just want to mention that SimpleBridge has had a dependency to a certain version of Yaws because it has used its own copy of the yaws_api.hrl include file. I have just remedied this by introducing some accessor functions to Yaws. So until these patches become mainstream you'll have to use the latest versions in respective repo.</p>
<p>Finally, just to be complete, here is how I could setup the use of some other HTTP engines:</p>
<pre class="brush: erlang">
start_link(inets) ->
inets:start(),
{ok, Pid} =
inets:start(httpd,
[{port, bfp:port()}
,{server_name, bfp:servername()},
,{bind_address, bfp:ip()}
,{server_root, "."}
,{document_root, bfp:docroot()}
,{modules, [?MODULE]}
,{mime_types, [{"css", "text/css"},
{"js", "text/javascript"},
{"html", "text/html"}]}
]),
link(Pid),
{ok, Pid};
start_link(mochiweb) ->
mochiweb:start(),
Options = [{port, bfp:port()}
,{name, bfp:servername()}
,{ip, bfp:ip()}
,{loop, fun(Req) -> do_mochiweb(Req) end}
],
{ok, Pid} = mochiweb_http:start(Options),
link(Pid),
{ok, Pid}.
%% Inets
do(Info) ->
RequestBridge = simple_bridge:make_request(inets_request_bridge, Info),
ResponseBridge = simple_bridge:make_response(inets_response_bridge, Info),
bfp:run(RequestBridge, ResponseBridge).
do_mochiweb(Info) ->
RequestBridge = simple_bridge:make_request(mochiweb_request_bridge, {Info,"./www"}),
ResponseBridge = simple_bridge:make_response(mochiweb_response_bridge, {Info, "./www"}),
bfp:run(RequestBridge, ResponseBridge).
</pre>
<p>Cheers, Tobbe</p>
</div><!--! end .postcontent -->
</div><!--! end .post -->
<div class="row post">
<div class="three columns metainfo alpha">
<p>By: Tobbe</p>
</div>
<div class="nine columns postcontent omega">
<h1>External access to Intranet Polish</h1>
<p>We are making heavy use of Polish for all our translation efforts. So far we have been using our in-house personnel to do the actual translation work. However, increasing demands for both quality and quantity made us look for external translators. The problem was how to open up the external access to each and everyone of our internal developers running Polish.</p>
<p>The solution we now have cooked up (cred to cjk who did all the hard work based on a proof of concept of mine) uses Nginx as a reverse proxy. The Nginx server proxies an external requests to a developers Polish system. The way to address a particular developer is made by the external domain name. This external domain name is constructed as:</p>
<pre class="brush: erlang">http://<branch-name>.i18n.klarna.com</pre>
<p>The Nginx server will match on this and proxy the request to the right Polish system and developer. Now the cool thing here is that this Nginx configuration is operated by a Yaws appmod running on the same machine. This appmod provides a RESTlike interface that Polish understands. So when the developer starts his Polish instance, Polish talks to the Yaws system which loads the proper configuration into the Nginx proxy. Here is a picture describing it:</p>
<img class="twelve columns" src="http://redhoterlang.com/blob/9725997ed30107783686359195d7d1a0" />
<p>Enginxx is the name of the Yaws appmod and works as a switchboard, loading/unloading Nginx configurations on behalf of the developers Polish systems. Via the REST interface it is possible to create and remove Nginx configurations.</p>
<p>Since we have poked a hole in our firwall and is instructing Nginx to proxy incoming request we need to address the security. We don't want anyone to be able to setup a Nginx proxy configuration, hence we sign each REST request. To produce the Signature we make use of the users SSH key-pairs. Since we already are using gitosis to handle the access to our git repository, we easily can reuse our developers public SSH key to verify the signature produced by Polish (using the developers private SSH key). To be able to do this we had to write some code to leverage the existing SSH OTP library.</p>
<p>All this may look complicated but for the developers almost nothing has changed, they just have to add one new switch (-x) to the Polish start script. Our external translators receive a mail with the URL leading to the correct developers Polish system. The translator will log in as before using OpenID. It all seem to work very smooth and we are happy.</p>
<p>Cheers, Tobbe</p>
</div><!--! end .postcontent -->
</div>
<div class="row post">
<div class="three columns metainfo alpha">
<p>By: Samir</p>
</div><!--! end .metainfo -->
<div class="nine columns postcontent omega">
<h1>Headline</h1>
<p>Lorem ipsum dolor sit amet, <strong>consectetur</strong> adipiscing elit. Fusce in leo mi. Nullam eleifend augue vel mi ornare ut molestie nisi egestas. Curabitur magna tortor, venenatis nec fringilla accumsan, faucibus in purus. Donec ultricies bibendum risus. Vivamus turpis tellus, ultrices nec pretium eu, facilisis in purus. Aliquam lobortis enim vestibulum odio lacinia placerat et ac quam. Cras vel magna odio, in ultricies risus. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Suspendisse vulputate facilisis lacus, ut aliquam mi dignissim nec.</p>
<blockquote>Pellentesque eu urna felis. Curabitur est tortor, venenatis vel tristique sed, cursus vel justo.</blockquote>
<p>Nunc eros purus, vulputate et porttitor eu, lobortis at odio. Maecenas a augue felis, eget malesuada arcu. Integer tellus elit, vulputate at mattis vel, egestas quis erat. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla non velit sapien.</p>
<ul class="tabs">
<li><a class="active" href="#test">Tab 1</a></li>
<li><a href="#test2">Tab 2</a></li>
</ul>
<ul class="tabs-content">
<li class="active" id="testTab">
<p>Aenean quis nunc purus. Praesent auctor urna in mi fermentum viverra. Phasellus sed mauris ac tortor vestibulum interdum id id mauris. Donec consectetur massa nec arcu sollicitudin sit amet posuere dui lacinia.</p>
<ul>
<li>Pellentesque odio diam, convallis in mollis at, rutrum vitae nibh.</li>
<li>Duis purus ante, consequat et cursus eu, elementum eget massa. </li>
</ul>
</li>
<li id="test2Tab">
<p>Mauris sit amet est in lorem tempor convallis in egestas tellus. Phasellus suscipit, lectus vel congue mollis, dolor eros tincidunt eros, ut dictum eros neque eu neque. Nullam vitae ante dui, vel rutrum nibh. Donec porttitor suscipit elit nec interdum.</p>
<ol>
<li>Phasellus consequat erat nibh.</li>
<li>Nunc nunc erat, varius non eleifend et, consectetur sit amet massa.</li>
</ol>
<p>Proin porttitor velit quam. Praesent pharetra sem at tellus faucibus tempus. Morbi at ligula nisi, vel congue nisl. Vestibulum nibh urna, sodales at condimentum sed, tincidunt sed dolor.</p>
</li>
</ul>
</div><!--! end .postcontent -->
</div><!--! end .post -->
<div class="row post">
<div class="three columns metainfo alpha">
<p>By: Samir</p>
</div><!--! end .metainfo -->
<div class="nine columns postcontent omega">
<h1>Headline</h1>
<p>Lots of supercontent</p>
</div><!--! end .postcontent -->
</div><!--! end .post -->
</div><!--! end .container -->
</div><!--! end .mainarea -->
<footer>
<div class="container">
<h3>Footer</h3>
</div><!--! end .container -->
</footer>
<!-- JS
================================================== -->
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.js"></script>
<script>window.jQuery || document.write("<script src='javascripts/jquery-1.5.1.min.js'>\x3C/script>")</script>
<script src="javascripts/less-1.1.0.min.js"></script>
<script src="javascripts/app.js"></script>
<script src="http://alexgorbatchev.com/pub/sh/current/scripts/shCore.js"></script>
<script src="http://alexgorbatchev.com/pub/sh/current/scripts/shAutoloader.js"></script>
<script>
SyntaxHighlighter.defaults['tab-size'] = 2;
SyntaxHighlighter.defaults['gutter'] = false;
SyntaxHighlighter.defaults['toolbar'] = false;
SyntaxHighlighter.defaults['class-name'] = 'eleven columns code';
SyntaxHighlighter.autoloader(
'js jscript javascript http://alexgorbatchev.com/pub/sh/current/scripts/shBrushJScript.js',
'applescript http://alexgorbatchev.com/pub/sh/current/scripts/shBrushAppleScript.js',
'erlang http://alexgorbatchev.com/pub/sh/current/scripts/shBrushErlang.js',
'css http://alexgorbatchev.com/pub/sh/current/scripts/shBrushCss.js',
'python http://alexgorbatchev.com/pub/sh/current/scripts/shBrushPython.js',
'php http://alexgorbatchev.com/pub/sh/current/scripts/shBrushPhp.js',
'ruby http://alexgorbatchev.com/pub/sh/current/scripts/shBrushRuby.js',
'sql http://alexgorbatchev.com/pub/sh/current/scripts/shBrushSql.js',
'html http://alexgorbatchev.com/pub/sh/current/scripts/shBrushXml.js'
);
SyntaxHighlighter.all();
</script>
<!-- End Document
================================================== -->
</body>
</html>