<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:blogger='http://schemas.google.com/blogger/2008' xmlns:georss='http://www.georss.org/georss' xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-5001452664427688683</id><updated>2024-09-11T18:11:09.124+02:00</updated><category term="fun"/><category term="thinking"/><category term="security"/><category term="php"/><category term="network"/><category term="algorithm"/><category term="google"/><category term="optimisation"/><category term="epfl"/><category term="nosql"/><category term="smtp"/><category term="sql"/><category term="apache"/><category term="concurrent"/><category term="development"/><category term="gentoo"/><category term="java"/><category term="patterns"/><category term="web 2.0"/><category term="dns"/><category term="doodle clone"/><category term="j2ee"/><category term="opensource"/><category term="scalability"/><category term="seo"/><category term="ssl"/><category term="verisign"/><category term="browser"/><category term="bullshit"/><category term="cassandra"/><category term="cluster"/><category term="consistency"/><category term="dependency"/><category term="dnssec"/><category term="interview question"/><category term="maven"/><category term="md5"/><category term="presentation"/><category term="privacy"/><category term="proxy"/><category term="self"/><category term="servlet"/><category term="snapshot"/><category term="thumbshot"/><category term="tomcat"/><category term="webmardi"/><category term="wireless"/><category term="work"/><title type='text'>Benoit Perroud : concepts and cloud ready applications</title><subtitle type='html'>Cloud computing, web security, distributed databases, system scalability and availability, NoSQL trend, this blog tends to reduce the storm of my mind.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://benoitperroud.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5001452664427688683/posts/default'/><link rel='alternate' type='text/html' href='http://benoitperroud.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/5001452664427688683/posts/default?start-index=26&amp;max-results=25'/><author><name>KillerWhile</name><uri>http://www.blogger.com/profile/17113505481300913194</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://www.noisette.ch/wiki/images/Raquette18.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>96</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-5001452664427688683.post-734106723544108191</id><published>2011-08-05T22:48:00.005+02:00</published><updated>2011-08-08T10:03:47.282+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="cassandra"/><category scheme="http://www.blogger.com/atom/ns#" term="dependency"/><category scheme="http://www.blogger.com/atom/ns#" term="maven"/><category scheme="http://www.blogger.com/atom/ns#" term="servlet"/><category scheme="http://www.blogger.com/atom/ns#" term="tomcat"/><title type='text'>Cassandra, hector, maven and tomcat</title><content type='html'>Cassandra (v0.7 and 0.8), hector (version compatible with Cassandra), maven and tomcat bound together result in a warning at tomcat startup : &lt;br /&gt;
&lt;br /&gt;
&lt;blockquote&gt;&lt;b&gt;INFO: validateJarFile(/...&amp;lt;webappspath&amp;gt;.../WEB-INF/lib/servlet-api-2.5-20081211.jar) - jar not loaded. See Servlet Spec 2.3, section 9.7.2. Offending class: javax/servlet/Servlet.class&lt;/webappspath&gt;&lt;/b&gt;&lt;/blockquote&gt;&lt;br /&gt;
Nothing harmful here, but as we want to do things as clean as possible we should avoid violating Servlet Spec 2.3.&lt;br /&gt;
&lt;br /&gt;
So running a dependency:tree help to find out the guilty dependency :&lt;br /&gt;
&lt;br /&gt;
&lt;blockquote&gt;[INFO] +- me.prettyprint:hector-core:jar:0.8.0-2:compile&lt;br /&gt;
[INFO] |&amp;nbsp; +- org.apache.cassandra:cassandra-all:jar:0.8.1:compile&lt;br /&gt;
[INFO] |&amp;nbsp; |&amp;nbsp; +- org.apache.cassandra.deps:avro:jar:1.4.0-cassandra-1:compile&lt;br /&gt;
[INFO] |&amp;nbsp; |&amp;nbsp; |&amp;nbsp; \- org.mortbay.jetty:jetty:jar:6.1.22:compile&lt;br /&gt;
[INFO] |&amp;nbsp; |&amp;nbsp; |&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; \- org.mortbay.jetty:servlet-api:jar:2.5-20081211:compile&lt;/blockquote&gt;&lt;br /&gt;
Hum hum, &lt;b&gt;org.mortbay.jetty:servlet-api:jar:2.5-20081211&lt;/b&gt;. We found the responsible of the problem.&lt;br /&gt;
&lt;br /&gt;
Using &lt;i&gt;&amp;lt;dependencymanagement&amp;gt;&lt;/i&gt; in our &lt;i&gt;pom.xml&lt;/i&gt; file we will be able to mark this dependency as &lt;b&gt;provided&lt;/b&gt; and the problem should flight away :&lt;br /&gt;
&lt;blockquote&gt;&amp;nbsp; &amp;lt;dependencymanagement&amp;gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;dependencies&amp;gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;dependency&amp;gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;groupId&amp;gt;org.mortbay.jetty&amp;lt;/groupId&amp;gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;artifactId&amp;gt;servlet-api&amp;lt;/artifactId&amp;gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;version&amp;gt;2.5-20081211&amp;lt;/version&amp;gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;scope&amp;gt;provided&amp;lt;/scope&amp;gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/dependency&amp;gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/dependencies&amp;gt;&lt;br /&gt;
&amp;nbsp; &amp;lt;/dependencymanagement&amp;gt;&lt;br /&gt;
&lt;/blockquote&gt;Build, deploy, and that&#39;s it !</content><link rel='replies' type='application/atom+xml' href='http://benoitperroud.blogspot.com/feeds/734106723544108191/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/5001452664427688683/734106723544108191' title='1 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5001452664427688683/posts/default/734106723544108191'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5001452664427688683/posts/default/734106723544108191'/><link rel='alternate' type='text/html' href='http://benoitperroud.blogspot.com/2011/08/cassandra-hector-maven-and-tomcat.html' title='Cassandra, hector, maven and tomcat'/><author><name>KillerWhile</name><uri>http://www.blogger.com/profile/17113505481300913194</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://www.noisette.ch/wiki/images/Raquette18.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5001452664427688683.post-5590935634992654171</id><published>2011-07-16T21:38:00.003+02:00</published><updated>2011-08-04T11:18:25.823+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="algorithm"/><category scheme="http://www.blogger.com/atom/ns#" term="interview question"/><category scheme="http://www.blogger.com/atom/ns#" term="patterns"/><category scheme="http://www.blogger.com/atom/ns#" term="verisign"/><title type='text'>More Interview Questions</title><content type='html'>&lt;span style=&quot;font-size: small;&quot;&gt;All interviews are different, all candidates are different, all positions are different. The goal here is to provide some general questions to test engineering skills of candidates. These questions are common in recruiting process in technical companies like Google or Verisign.&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-size: large;&quot;&gt;How could you detect a loop in a linked list ?&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
It&#39;s say linked list, to be more precise you only have a pointer to the head of the list, and you know how to move to the next element of the list.&lt;br /&gt;
Of course you are not allowed to modify the list at all. And obviously  you should try to propose an algorithm that do it in the most efficient way, let say you should try to target O(n).&lt;br /&gt;
&lt;br /&gt;
In more programmer oriented : write a function A that take as parameter the first element of a  List and return a boolean with value true if the given List has a loop, false otherwise. You know how to pass to the next element of the List : just call element.next.&lt;br /&gt;
&lt;br /&gt;
For those who want to try to answer by themself, stop reading here.&lt;br /&gt;
&lt;br /&gt;
One good  answer is to have 2 iterators that walk through the elements of the List, but at different speed. One iterator move from 1 element per iteration, the second one move from 2 elements per iteration, and check if it meet the first iterator during it&#39;s move. How fast goes the second iterator can be configurable.&lt;br /&gt;
If at one point the second iterator (fast moving) meet the first one, there is a loop in the List. If the second iterator reach the end of the List, there is obviously no loop.&lt;br /&gt;
&lt;br /&gt;
In pseudo code, it would be :&lt;br /&gt;
&lt;blockquote&gt;&lt;b&gt;function&lt;/b&gt; A (head element of List &lt;i&gt;list&lt;/i&gt;) &lt;b&gt;return&lt;/b&gt; boolean :&lt;br /&gt;
&lt;i&gt;it1&lt;/i&gt; is initialized to the head element of &lt;i&gt;list&lt;/i&gt;&lt;br /&gt;
&lt;i&gt;it2&lt;/i&gt; is initialized to the head element of &lt;i&gt;list&lt;/i&gt;&lt;br /&gt;
&lt;b&gt;while&lt;/b&gt; &lt;i&gt;it2&lt;/i&gt; has not reach end &lt;i&gt; list&lt;/i&gt; &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;b&gt;for&lt;/b&gt; number of element &lt;i&gt;it2&lt;/i&gt; will move&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; it2 move to the next element.&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;b&gt;if&lt;/b&gt; the element of &lt;i&gt;it2&lt;/i&gt; is equal to the element of &lt;i&gt;it1&lt;/i&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; there is a loop ! return &lt;b&gt;true&lt;/b&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;i&gt;it1&lt;/i&gt; move to the next element&lt;br /&gt;
there is no loop. return &lt;b&gt;false&lt;/b&gt;&lt;/blockquote&gt;As targeted, this algorithm will be on complexity of O(n), as the worst case is the last element looping to itself. When the last element loop to the first one, the algorithm will detect the loop in n / speed of the second iterator.&lt;br /&gt;
And finally, the memory footprint is  very low.&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-size: large;&quot;&gt;What are the advantages of a LinkedList over an ArrayList ?&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
This  question is more often ask in a different way : what are the &lt;b&gt;differences&lt;/b&gt; between a &lt;i&gt;LinkedList&lt;/i&gt; and an &lt;i&gt;ArrayList&lt;/i&gt;. But turning the question up side down like here is a bit more interesting. So what are the &lt;b&gt;advantages&lt;/b&gt; ?&lt;br /&gt;
&lt;br /&gt;
The basic advantage of the &lt;i&gt;LinkedList&lt;/i&gt; is its O(1) insertion and deletion complexity for &lt;b&gt;any&lt;/b&gt; given element, while &lt;i&gt;ArrayList&lt;/i&gt; need to move back or forth the elements after the given element. Another advantage is the  linearly increasing  memory footprint of a &lt;i&gt;LinkedList&lt;/i&gt;, when &lt;i&gt;ArrayList&lt;/i&gt; memory (still linear but) increases by steps, and then perform sometimes costly memory copies. With such memory copies &lt;i&gt;ArrayList&lt;/i&gt; have an&lt;i&gt; amotized complexity in O(1)&lt;/i&gt;, but this leads to non deterministic operations, which are unwanted when dealing with tight SLAs.&lt;br /&gt;
One more hidden advantage of the &lt;i&gt;LindekList&lt;/i&gt; is still in the topic of memory usage : it does not require to allocate blocks of memory, elements stored in &lt;i&gt;LinkedList&lt;/i&gt; do not require to be allocated in contiguous memory. Just notice that  fragmentation of  the memory is not always seen as good point.</content><link rel='replies' type='application/atom+xml' href='http://benoitperroud.blogspot.com/feeds/5590935634992654171/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/5001452664427688683/5590935634992654171' title='2 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5001452664427688683/posts/default/5590935634992654171'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5001452664427688683/posts/default/5590935634992654171'/><link rel='alternate' type='text/html' href='http://benoitperroud.blogspot.com/2011/07/more-interview-questions.html' title='More Interview Questions'/><author><name>KillerWhile</name><uri>http://www.blogger.com/profile/17113505481300913194</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://www.noisette.ch/wiki/images/Raquette18.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5001452664427688683.post-8976806790282722602</id><published>2011-03-07T14:32:00.001+01:00</published><updated>2011-07-06T16:02:15.877+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="nosql"/><category scheme="http://www.blogger.com/atom/ns#" term="presentation"/><category scheme="http://www.blogger.com/atom/ns#" term="webmardi"/><title type='text'>NoSQL Overview @Webmardi</title><content type='html'>Tuesday 1st of March 2011 I gave an overview of NoSQL at the &lt;a href=&quot;http://www.webmardi.ch/&quot;&gt;Webmardi&lt;/a&gt; monthly event. The presentation was hosted by Webdoc. Thanks all for the warm welcome !&lt;br /&gt;
&lt;br /&gt;
Some pictures :&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4iz7m0421oRoyTKEcuWKROF0Wf_MoVuNO6eYovOaJbvPuftqxeoKxIG9g-1NYFTr8UfN3v94e-hkRqXfcuzoD_HwT1eDuanLLdqJZeirhtnmGP-jgZGtyNWG2lIrtDSx3_U0AtE91KG34/s1600/0d9504ab53284a72966f8ff06012411d_7.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4iz7m0421oRoyTKEcuWKROF0Wf_MoVuNO6eYovOaJbvPuftqxeoKxIG9g-1NYFTr8UfN3v94e-hkRqXfcuzoD_HwT1eDuanLLdqJZeirhtnmGP-jgZGtyNWG2lIrtDSx3_U0AtE91KG34/s320/0d9504ab53284a72966f8ff06012411d_7.jpg&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhxlI4v-OzQmG0gKdGCSCER4KneZVp4T4vALqp7N_U5GgOm2Bkwnv5FyyVIEo_rC21CIZdhrfSF4onHGaEicMiG8haUsf5YJ3Hn0PUhtLYXS6EJAMUX9M3yF-tkti6a3LM0Vj85e_kcCbOq/s1600/tc8hy.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;239&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhxlI4v-OzQmG0gKdGCSCER4KneZVp4T4vALqp7N_U5GgOm2Bkwnv5FyyVIEo_rC21CIZdhrfSF4onHGaEicMiG8haUsf5YJ3Hn0PUhtLYXS6EJAMUX9M3yF-tkti6a3LM0Vj85e_kcCbOq/s320/tc8hy.jpg&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
&lt;br /&gt;
The slides are available on Slideshare : &lt;a href=&quot;http://www.slideshare.net/benoitperroud/nosql-overview-implementation-free&quot;&gt;NoSQL Overview, implementation free&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
It is called &quot;Implementation free&quot; because I didn&#39;t want to focus on a particular implementation of a NoSQL datasore, but rather generalize concepts of &quot;What is NoSQL&quot;. And it&#39;s a tricky answer to formulate :)&lt;br /&gt;
&lt;br /&gt;
So what is NoSQL ? It&#39;s a family of datastores that does not have SQL as main data access pattern.&lt;br /&gt;
&lt;br /&gt;
The presentation was hosted by Webdoc :&amp;nbsp;&lt;a href=&quot;http://www.webdoc.com/&quot;&gt;http://www.webdoc.com&lt;/a&gt;.</content><link rel='replies' type='application/atom+xml' href='http://benoitperroud.blogspot.com/feeds/8976806790282722602/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/5001452664427688683/8976806790282722602' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5001452664427688683/posts/default/8976806790282722602'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5001452664427688683/posts/default/8976806790282722602'/><link rel='alternate' type='text/html' href='http://benoitperroud.blogspot.com/2011/03/nosql-overview-webmardi.html' title='NoSQL Overview @Webmardi'/><author><name>KillerWhile</name><uri>http://www.blogger.com/profile/17113505481300913194</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://www.noisette.ch/wiki/images/Raquette18.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4iz7m0421oRoyTKEcuWKROF0Wf_MoVuNO6eYovOaJbvPuftqxeoKxIG9g-1NYFTr8UfN3v94e-hkRqXfcuzoD_HwT1eDuanLLdqJZeirhtnmGP-jgZGtyNWG2lIrtDSx3_U0AtE91KG34/s72-c/0d9504ab53284a72966f8ff06012411d_7.jpg" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5001452664427688683.post-444877559751254594</id><published>2011-01-06T12:40:00.006+01:00</published><updated>2011-01-06T13:33:38.595+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="algorithm"/><category scheme="http://www.blogger.com/atom/ns#" term="concurrent"/><category scheme="http://www.blogger.com/atom/ns#" term="consistency"/><category scheme="http://www.blogger.com/atom/ns#" term="nosql"/><category scheme="http://www.blogger.com/atom/ns#" term="patterns"/><category scheme="http://www.blogger.com/atom/ns#" term="scalability"/><title type='text'>Eventually Consistency demystified</title><content type='html'>In my crusade into the NoSQL world, &lt;a href=&quot;http://en.wikipedia.org/wiki/Eventual_consistency&quot;&gt;&lt;span style=&quot;font-style: italic;&quot;&gt;Eventually Consistency&lt;/span&gt;&lt;/a&gt; is everywhere. I want to demystify this property a little bit here.&lt;br /&gt;&lt;br /&gt;But let&#39;s begin with an example to have the same base for the  discussion :&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Let &quot;Node1&quot;, &quot;Node2&quot; and &quot;Node3&quot; be three nodes (servers) that are part of our distributed datastore.&lt;/li&gt;&lt;li&gt;Let &quot;User A&quot;, &quot;User B&quot;, &quot;User c&quot; be three users wanting to read and write data in our fictive distributed datastore.&lt;/li&gt;&lt;/ul&gt;At time (1), &quot;User A&quot; write the value &quot;A&quot; to &quot;Node1&quot;. &quot;Node1&quot; will replicate asynchronously this value to both &quot;Node2&quot; and &quot;Node3&quot; (specific to my example).&lt;br /&gt;At time (2) the write call of &quot;Node A&quot; returns. But the replication of value &quot;A&quot; hasn&#39;t been completely propagate to &quot;Node2&quot; and &quot;Node3&quot;.&lt;br /&gt;At time (3), &quot;User B&quot; and &quot;User C&quot; will read value &quot;A&quot; from &quot;Node1&quot; and &quot;Node2&quot; respectively. &quot;User B&quot; got the latest value (because it reads the node which initiate the update), &quot;User C&quot; will read  either the old or the new version of &quot;A&quot;,  but without any  guarantee regarding what it will read.&lt;br /&gt;&lt;br /&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEii212-LlgyG1CSJEBNYGdbrTBeye_t4YY1m7elZzkIicGVkMSq7abFhcBurUSKLat6YvSntwik6dLq5xEbe1VfBK4XhDG01JVZE6Hvmktyr6zSXXJF7Lb0oYxYN1Yvd31uS6K5KhOHFCeu/s1600/Eventually_consistency_read.png&quot;&gt;&lt;img style=&quot;cursor: pointer; width: 400px; height: 334px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEii212-LlgyG1CSJEBNYGdbrTBeye_t4YY1m7elZzkIicGVkMSq7abFhcBurUSKLat6YvSntwik6dLq5xEbe1VfBK4XhDG01JVZE6Hvmktyr6zSXXJF7Lb0oYxYN1Yvd31uS6K5KhOHFCeu/s400/Eventually_consistency_read.png&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5559038076868842066&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;In a future time (5), &quot;User B&quot; and &quot;User C&quot; re-read value &quot;A&quot; and then got the same value. At this point of time, the datastore is consistent.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size:130%;&quot;&gt;Immediate Consistency&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;In a &lt;a href=&quot;http://en.wikipedia.org/wiki/Immediate_consistency&quot;&gt;&lt;span style=&quot;font-style: italic;&quot;&gt;Immediate Consistency&lt;/span&gt;&lt;/a&gt;, opposing &lt;span style=&quot;font-style: italic;&quot;&gt;Eventually Consistency&lt;/span&gt;, the write call from &quot;User A&quot; should wait till the replication is done on other nodes before returning, and replica nodes (&quot;Node2&quot; and &quot;Node3&quot;) should be synchronized to expose the new value at the same time.&lt;br /&gt;&lt;br /&gt;Moreover, if &quot;Node1&quot; is unable to talk to &quot;Node2&quot;, the write replication will probably fail then the write call from &quot;User A&quot; will fail.&lt;br /&gt;&lt;br /&gt;As we can notice, &lt;span style=&quot;font-style: italic;&quot;&gt;Immediate Consistency&lt;/span&gt;  is hard to scale (see &lt;a href=&quot;http://en.wikipedia.org/wiki/Two-phase_commit_protocol&quot;&gt;two-phase commit&lt;/a&gt; or &lt;a href=&quot;http://en.wikipedia.org/wiki/Paxos_algorithm&quot;&gt;paxos algorithm&lt;/a&gt;), because it increases the latency of the writes and makes the system not redundant to failure.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size:130%;&quot;&gt;Trade-off for scaling writes&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-style: italic;&quot;&gt;Eventually Consistency&lt;/span&gt; is then a  trade-off for scaling writes that seems reasonable in certain use-cases.</content><link rel='replies' type='application/atom+xml' href='http://benoitperroud.blogspot.com/feeds/444877559751254594/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/5001452664427688683/444877559751254594' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5001452664427688683/posts/default/444877559751254594'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5001452664427688683/posts/default/444877559751254594'/><link rel='alternate' type='text/html' href='http://benoitperroud.blogspot.com/2011/01/eventually-consistency-demystified.html' title='Eventually Consistency demystified'/><author><name>KillerWhile</name><uri>http://www.blogger.com/profile/17113505481300913194</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://www.noisette.ch/wiki/images/Raquette18.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEii212-LlgyG1CSJEBNYGdbrTBeye_t4YY1m7elZzkIicGVkMSq7abFhcBurUSKLat6YvSntwik6dLq5xEbe1VfBK4XhDG01JVZE6Hvmktyr6zSXXJF7Lb0oYxYN1Yvd31uS6K5KhOHFCeu/s72-c/Eventually_consistency_read.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5001452664427688683.post-345770704783454126</id><published>2010-12-23T10:38:00.004+01:00</published><updated>2010-12-23T11:21:38.196+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="algorithm"/><category scheme="http://www.blogger.com/atom/ns#" term="dns"/><category scheme="http://www.blogger.com/atom/ns#" term="dnssec"/><title type='text'>DNSSEC NSEC3 domain hash computation algorithm</title><content type='html'>DNSSEC is a DNS extension in order to authenticate  and ensure integrity of DNS responses, in order to offers protection against DNS spoofing.&lt;br /&gt;&lt;br /&gt;DNSSEC comes with two &quot;denial of existence&quot; mechanism : NSEC (RFCs 4033, 4034, 4035) and NSEC3 (RFC 5155).&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size:130%;&quot;&gt;Now how &quot;denial of existence&quot; works ?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;When a query is performed on a non-existing domain, a specific answer is returned to the resolution client, given the closest  domains that are alphabetically before and after the queried domain. But what is very sensible in this way of proving the non-existence of a domain is that we can easily enumerate the whole zone.&lt;br /&gt;&lt;br /&gt;That&#39;s why NSEC3 was designed to prove the non-existence of a domain, but in the same time to avoid the zone walk through.&lt;br /&gt;Instead of simply returning the closest domains, it returns a hash of the domains.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size:130%;&quot;&gt;How to compute NSEC3 Hash ?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I will detail a little bit how this NSESC3 hash is computed :&lt;br /&gt;&lt;br /&gt;I you have a look at a zone, you will find additional records, like &lt;span style=&quot;font-style: italic;&quot;&gt;NSEC3PARAM&lt;/span&gt; :&lt;br /&gt;&lt;blockquote style=&quot;font-style: italic;&quot;&gt;example.com. NSEC3PARAM 1 0 12 aabbccdd&lt;/blockquote&gt;The format of such record is composed of :&lt;br /&gt;&lt;ul&gt;&lt;li&gt;an algorithm field. 1 means SHA1&lt;/li&gt;&lt;li&gt;a flags field&lt;/li&gt;&lt;li&gt;an iterations field&lt;/li&gt;&lt;li&gt;a salt, represented as a sequence of case-insensitive &lt;span style=&quot;font-weight: bold;&quot;&gt;hexadecimal digits&lt;/span&gt;.&lt;/li&gt;&lt;/ul&gt;Then the hashing algorithm is given by :&lt;br /&gt;&lt;pre class=&quot;newpage&quot;&gt; IH(salt, x, 0) = H(x || salt), and&lt;br /&gt;IH(salt, x, k) = H(IH(salt, x, k-1) || salt), if k &gt; 0&lt;br /&gt;&lt;/pre&gt;With my &lt;span style=&quot;font-style: italic;&quot;&gt;example.com&lt;/span&gt; domain, the hash algorithm will be :&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-style: italic;&quot;&gt;IH(fromHexStringToByte(&quot;aabbccdd&quot;), toCanonicalWireFormat(&quot;example.com&quot;), 12)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-style: italic;&quot;&gt;fromHexStringToByte&lt;/span&gt; is a base 16 decoder : &lt;span style=&quot;font-style: italic;&quot;&gt;fromHexStringToByte(&quot;aabbccdd&quot;) = [0xaa, 0xbb, 0xcc, 0xdd]&lt;/span&gt;. See &lt;a href=&quot;https://tools.ietf.org/html/rfc4648&quot;&gt;RFC4648&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-style: italic;&quot;&gt;toCanonicalWireFormat&lt;/span&gt; convert the domain in wire format using its canonical form : &lt;span style=&quot;font-style: italic;&quot;&gt;toCanonicalWireFormat(&quot;example.com&quot;) = [0x07, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00]&lt;/span&gt;. See &lt;a href=&quot;https://tools.ietf.org/html/rfc4034#section-6.2&quot;&gt;RFC4034&lt;/a&gt; (canonical form), &lt;a href=&quot;https://tools.ietf.org/html/rfc3845#section-2.3&quot;&gt;RFC3845&lt;/a&gt; (wire format)&lt;br /&gt;&lt;br /&gt;And that&#39;s it, you are now able to compute the NSEC3 hash of your favourite domain. You just need to wait for NSEC3PARAM to be published in the respective zone to got all the necessary parameters :)</content><link rel='replies' type='application/atom+xml' href='http://benoitperroud.blogspot.com/feeds/345770704783454126/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/5001452664427688683/345770704783454126' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5001452664427688683/posts/default/345770704783454126'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5001452664427688683/posts/default/345770704783454126'/><link rel='alternate' type='text/html' href='http://benoitperroud.blogspot.com/2010/12/dnssec-nsec3-domain-hash-computation.html' title='DNSSEC NSEC3 domain hash computation algorithm'/><author><name>KillerWhile</name><uri>http://www.blogger.com/profile/17113505481300913194</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://www.noisette.ch/wiki/images/Raquette18.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5001452664427688683.post-887629624219599225</id><published>2010-11-19T14:19:00.004+01:00</published><updated>2010-11-19T14:28:53.890+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="development"/><category scheme="http://www.blogger.com/atom/ns#" term="java"/><category scheme="http://www.blogger.com/atom/ns#" term="network"/><title type='text'>Using java.net.InetAddress.getByName() to validate an IP Address may be too permissive</title><content type='html'>&lt;span style=&quot;font-style: italic;&quot;&gt;java.net.InetAddress.getByName()&lt;/span&gt; static function can be used for validating a given IP Address.&lt;br /&gt;&lt;br /&gt;But doing that way you need to pay attention to certain side effects border values :&lt;br /&gt;&lt;pre&gt;String ip = &quot;1.2.3.4&quot;; // valid IP Address&lt;br /&gt;InetAddress address = InetAddress.getByName( ip );&lt;br /&gt;Assert.assertEquals( ip, address.getHostAddress() ); // Pass. OK&lt;br /&gt;&lt;br /&gt;String ip = &quot;1.2.3&quot;; // invalid IP Address&lt;br /&gt;InetAddress address = InetAddress.getByName( ip );&lt;br /&gt;Assert.assertEquals( ip, address.getHostAddress() ); // Pass. &lt;span style=&quot;font-weight: bold;&quot;&gt;KO&lt;/span&gt; !&lt;/pre&gt;If you have a look a little  deeper, you will see that &lt;span style=&quot;font-style: italic;&quot;&gt;1.2.3&lt;/span&gt; is transformed in &lt;span style=&quot;font-style: italic;&quot;&gt;1.2.0.3&lt;/span&gt;, which after transformation become a valid IP Address.&lt;br /&gt;&lt;br /&gt;Having that in mind, a IP Address validation function can look like :&lt;br /&gt;&lt;pre&gt;public static boolean validateIpAddress( String anIpAddress ) {&lt;br /&gt; try {&lt;br /&gt;  InetAddress address = InetAddress.getByName( anIpAddress );&lt;br /&gt;  return address.getHostAddress().equals( anIpAddress );&lt;br /&gt; } catch (final UnknownHostException e) {&lt;br /&gt;  return false;&lt;br /&gt; }&lt;br /&gt;}&lt;/pre&gt;</content><link rel='replies' type='application/atom+xml' href='http://benoitperroud.blogspot.com/feeds/887629624219599225/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/5001452664427688683/887629624219599225' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5001452664427688683/posts/default/887629624219599225'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5001452664427688683/posts/default/887629624219599225'/><link rel='alternate' type='text/html' href='http://benoitperroud.blogspot.com/2010/11/using-javanetinetaddressgetbyname-to.html' title='Using java.net.InetAddress.getByName() to validate an IP Address may be too permissive'/><author><name>KillerWhile</name><uri>http://www.blogger.com/profile/17113505481300913194</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://www.noisette.ch/wiki/images/Raquette18.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5001452664427688683.post-8776224348796041777</id><published>2010-10-09T13:46:00.003+02:00</published><updated>2010-10-09T14:16:15.889+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="dns"/><category scheme="http://www.blogger.com/atom/ns#" term="verisign"/><category scheme="http://www.blogger.com/atom/ns#" term="work"/><title type='text'>Moving from ELCA to Verisign</title><content type='html'>I had a great time at &lt;a href=&quot;http://www.elca.ch&quot;&gt;ELCA Informatique SA&lt;/a&gt;, working for almost 3 years on &lt;a href=&quot;http://www.secutix.com&quot;&gt;Secutix, a complete ticketing system&lt;/a&gt;. But now it&#39;s time for me to move forward and see something else : different projects, different colleagues, different cultures, speak more English, nearer from home, and so on...&lt;br /&gt;&lt;br /&gt;That&#39;s why I will move to &lt;a href=&quot;http://www.verisign.com&quot;&gt;Verisign&lt;/a&gt;, beginning the 2nd of November (the 1st is day off :)). Working on the heart of Internet (aka &lt;a href=&quot;http://en.wikipedia.org/wiki/Domain_Name_System&quot;&gt;DNS&lt;/a&gt;) is some kind of child&#39;s dream which I will be able to realize ! I&#39;m really excited to see how &lt;a href=&quot;http://en.wikipedia.org/wiki/Root_nameserver&quot;&gt;root name servers&lt;/a&gt; work, what&#39;s behind &lt;a href=&quot;http://en.wikipedia.org/wiki/Domain_name_registrar&quot;&gt;Registrars&lt;/a&gt; (aka &lt;a href=&quot;http://en.wikipedia.org/wiki/Domain_name_registry&quot;&gt;registry&lt;/a&gt;), implementing &lt;a href=&quot;http://en.wikipedia.org/wiki/Dnssec&quot;&gt;DNSSEC&lt;/a&gt; or what means 1 billion transactions a day.&lt;br /&gt;&lt;br /&gt;I really look forward to start there, and in the same time wish all the best to the Secutix team !</content><link rel='replies' type='application/atom+xml' href='http://benoitperroud.blogspot.com/feeds/8776224348796041777/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/5001452664427688683/8776224348796041777' title='1 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5001452664427688683/posts/default/8776224348796041777'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5001452664427688683/posts/default/8776224348796041777'/><link rel='alternate' type='text/html' href='http://benoitperroud.blogspot.com/2010/10/moving-from-elca-to-verisign.html' title='Moving from ELCA to Verisign'/><author><name>KillerWhile</name><uri>http://www.blogger.com/profile/17113505481300913194</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://www.noisette.ch/wiki/images/Raquette18.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5001452664427688683.post-2225593076371054313</id><published>2010-08-02T11:19:00.004+02:00</published><updated>2010-08-03T11:35:08.848+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="java"/><category scheme="http://www.blogger.com/atom/ns#" term="security"/><category scheme="http://www.blogger.com/atom/ns#" term="ssl"/><title type='text'>Dealing with old SSL certificats (algorithm check failed: MD2withRSA is disabled)</title><content type='html'>I faced the problem of &lt;span style=&quot;font-style: italic;&quot;&gt;SSLHandShakeException&lt;/span&gt;, or &quot;algorithm check failed: &lt;span style=&quot;font-style: italic;&quot;&gt;MD2withRSA&lt;/span&gt; is disabled&quot; when upgrading above java 1.6.0_17.&lt;br /&gt;&lt;br /&gt;The source of problem is well known, the &lt;span style=&quot;font-style: italic;&quot;&gt;MD2withRSA&lt;/span&gt; has been removed from the JVM because it is no more secure (References : &lt;span id=&quot;summary_alias_container&quot;&gt;&lt;span id=&quot;short_desc_nonedit_display&quot;&gt;&lt;a href=&quot;https://bugzilla.redhat.com/show_bug.cgi?id=CVE-2009-2409&quot;&gt;CVE-2009-2409 deprecate MD2 in SSL cert validation&lt;/a&gt;, &lt;a href=&quot;http://www.oracle.com/technetwork/java/javase/index-140291.html&quot;&gt;Sun java 1.6u17 release notes&lt;/a&gt;)&lt;/span&gt;&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Lot of posts around the problem give the solution to update the certificate to use another signature algorithm, for example &lt;span style=&quot;font-style: italic;&quot;&gt;SHA1withRSA&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;But what to do when the certificate is not under our hands ?&lt;br /&gt;&lt;br /&gt;I will try to explain the problem and how I solved it.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size:180%;&quot;&gt;Analyse the certificate&#39;s chain&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;First of all is to analyse the chain of certificate to see which one is using the deprecated algorithm.&lt;br /&gt;&lt;br /&gt;The following command will print all the certificates in the chain and store them under the names level0.pem, level1.pem and so on.&lt;br /&gt;&lt;blockquote  style=&quot;font-family:courier new;&quot;&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;openssl&lt;/span&gt; &lt;span style=&quot;font-weight: bold;&quot;&gt;s_client&lt;/span&gt; &lt;span style=&quot;font-weight: bold;&quot;&gt;-showcerts&lt;/span&gt; -connect xxxxxxxxxxxxxxxxx:443 &lt; /dev/null | awk -v c=-1 &#39;/-----BEGIN CERTIFICATE-----/{inc=1;c++} inc {print &gt; (&quot;level&quot; c &quot;.pem&quot;)}/---END CERTIFICATE-----/{inc=0}&#39;; for i in level?.pem; do &lt;span style=&quot;font-weight: bold;&quot;&gt;openssl x509&lt;/span&gt; -noout -serial -subject -issuer -in &quot;$i&quot;; done&lt;/blockquote&gt;The output given in my case :&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;Cert1, serial=xxxxxxxxxxxxxxxxxxxxx&lt;/span&gt;&lt;br /&gt;subject= xxxxxxxxxxxxxxxxxxxxxxxx&lt;br /&gt;issuer= /C=ZA/O=Thawte Consulting (Pty) Ltd./CN=Thawte SGC CA&lt;/li&gt;&lt;li&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;Cert2, serial=30000002&lt;/span&gt;&lt;br /&gt;subject= /C=ZA/O=Thawte Consulting (Pty) Ltd./CN=Thawte SGC CA&lt;br /&gt;issuer= /C=US/O=VeriSign, Inc./OU=Class 3 Public Primary Certification Authority&lt;/li&gt;&lt;li&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;Cert3, serial=70BAE41D10D92934B638CA7B03CCBABF&lt;/span&gt;&lt;br /&gt;subject= /C=US/O=VeriSign, Inc./OU=Class 3 Public Primary Certification Authority&lt;br /&gt;issuer= /C=US/O=VeriSign, Inc./OU=Class 3 Public Primary Certification Authority&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;We have a chain of 3 certificates, Cert1 signed by Cert2 signed by Cert3 signed by Cert3 (selfsigned).&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-style: italic;&quot;&gt;Note : the first error here is that the webserver gives explicitly the entire chain of certificates. Thus the change of any root certificate provided by the jre will not be taken into account automatically.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Digging into the details of the third certificate (&lt;span style=&quot;font-weight: bold;&quot;&gt;openssl x509&lt;/span&gt; -in level2.pem &lt;span style=&quot;font-weight: bold;&quot;&gt;-text&lt;/span&gt;) show that this certificate is signed with the old algorithm :&lt;br /&gt;&lt;blockquote&gt;Certificate:&lt;br /&gt;Data:&lt;br /&gt;    Version: 1 (0x0)&lt;br /&gt;    Serial Number:&lt;br /&gt;        70:ba:e4:1d:10:d9:29:34:b6:38:ca:7b:03:cc:ba:bf&lt;br /&gt;    &lt;span style=&quot;font-weight: bold;&quot;&gt;Signature Algorithm: md2WithRSAEncryption&lt;/span&gt;&lt;br /&gt;    Issuer: C=US, O=VeriSign, Inc., OU=Class 3 Public Primary Certification Authority&lt;br /&gt;    Validity&lt;br /&gt;        Not Before: Jan 29 00:00:00 1996 GMT&lt;br /&gt;        Not After : Aug  1 23:59:59 2028 GMT&lt;/blockquote&gt;So not only the way of providing the full chain is wrong in point of view of the server configuration, but the last certificate was never updated and thus still use the deprecated signature algorigthm.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size:180%;&quot;&gt;Correct the certificate&#39;s chain&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Now we have identified the weak link of the chain, what&#39;s the next step ?&lt;br /&gt;&lt;br /&gt;The key point here is to correct the certificate&#39;s chain in order to make it more compliant to the standards :&lt;br /&gt;&lt;br /&gt;As the third certificate is a well know root certificate (&lt;span style=&quot;font-style: italic;&quot;&gt;named &lt;/span&gt;&lt;span style=&quot;font-weight: bold; font-style: italic;&quot;&gt;verisignclass3ca&lt;/span&gt;&lt;span style=&quot;font-style: italic;&quot;&gt; in the jre cacerts&lt;/span&gt;), a working version of it is provided in the cacert of java sun (&lt;span style=&quot;font-style: italic;&quot;&gt;debian oriented commande line, with &quot;changeit&quot; as password&lt;/span&gt;) :&lt;br /&gt;&lt;blockquote  style=&quot;font-family:courier new;&quot;&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;keytool -keystore&lt;/span&gt; /etc/java-6-sun/security/cacerts -exportcert -alias &quot;verisignclass3ca&quot; | &lt;span style=&quot;font-weight: bold;&quot;&gt;openssl x509 -inform der -text&lt;/span&gt;&lt;/blockquote&gt;will output :&lt;br /&gt;&lt;blockquote&gt;Certificate:&lt;br /&gt;Data:&lt;br /&gt;    Version: 1 (0x0)&lt;br /&gt;    Serial Number:&lt;br /&gt;        3c:91:31:cb:1f:f6:d0:1b:0e:9a:b8:d0:44:bf:12:be&lt;br /&gt;    &lt;span style=&quot;font-weight: bold;&quot;&gt;Signature Algorithm: sha1WithRSAEncryption&lt;/span&gt;&lt;br /&gt;    Issuer: C=US, O=VeriSign, Inc., OU=Class 3 Public Primary Certification Authority&lt;br /&gt;    Validity&lt;br /&gt;        Not Before: Jan 29 00:00:00 1996 GMT&lt;br /&gt;        Not After : Aug  2 23:59:59 2028 GMT&lt;/blockquote&gt;which is the same as before, but with &lt;span style=&quot;font-style: italic;&quot;&gt;sha1WithRSAEncryption&lt;/span&gt; instead of &lt;span style=&quot;font-style: italic;&quot;&gt;md2WithRSAEncryption&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Thus we can simply remove it from the chain and validate normally the certificate&#39;s chain &lt;span style=&quot;font-weight: bold;&quot;&gt;with only Cert1 and Cert2&lt;/span&gt;. The validation from Cert2 to &quot;verisignclass3ca&quot; will be automagically done.&lt;br /&gt;&lt;br /&gt;To be able to do this, we need to create a custom &lt;span style=&quot;font-style: italic;&quot;&gt;X509TrustManager&lt;/span&gt; which will behave the following :&lt;br /&gt;&lt;ol&gt;&lt;li&gt;if the certificate&#39;s serial is the one of Cert1 (serial=xxxxxxxxxxxxxxxxxxxxx), then &lt;span style=&quot;font-weight: bold;&quot;&gt;remove the last certificate of the chain and revalidate&lt;/span&gt;.&lt;/li&gt;&lt;li&gt;In all other cases, validate normally the certificate&#39;s chain.&lt;/li&gt;&lt;/ol&gt;Thus the custom &lt;span style=&quot;font-style: italic;&quot;&gt;X509TrustManager &lt;/span&gt;act as delegate, with one little variation (&lt;span style=&quot;font-style: italic;&quot;&gt;note : if someone know a easier way to instantiate the default &lt;/span&gt;&lt;span style=&quot;font-style: italic;&quot;&gt;TrustManagerFactory&lt;/span&gt;&lt;span style=&quot;font-style: italic;&quot;&gt; of &lt;/span&gt;&lt;span style=&quot;font-style: italic;&quot;&gt;TrustManager&lt;/span&gt;&lt;span style=&quot;font-style: italic;&quot;&gt;, please leave me a comment&lt;/span&gt;). Refer to my article about &lt;a href=&quot;http://benoitperroud.blogspot.com/2010/08/java-and-certificates-mess-blind-ssl.html&quot;&gt;blind SSL factory for httpClients&lt;/a&gt; to see how to pass a custom &lt;span style=&quot;font-style: italic;&quot;&gt;TrustManager&lt;/span&gt; to a SSL factory.&lt;br /&gt;&lt;br /&gt;My custom &lt;span style=&quot;font-style: italic;&quot;&gt;X509TrustManager&lt;/span&gt; class will finally look as the follow :&lt;br /&gt;&lt;pre&gt;public class CustomX509TrustManager implements X509TrustManager {&lt;br /&gt;&lt;br /&gt;   X509TrustManager delegate = null;&lt;br /&gt;&lt;br /&gt;   public CustomX509TrustManager(KeyStore keystore) throws NoSuchAlgorithmException, KeyStoreException, CertificateException {&lt;br /&gt;    // Instantiate the default X509TrustManager&lt;br /&gt;    TrustManagerFactory factory = TrustManagerFactory&lt;br /&gt;           .getInstance(TrustManagerFactory.getDefaultAlgorithm());&lt;br /&gt;       factory.init(keystore);&lt;br /&gt;       TrustManager[] trustManagers = factory.getTrustManagers();&lt;br /&gt;       if (trustManagers != null &amp;amp;&amp;amp; trustManagers.length &gt; 0) {&lt;br /&gt;           for (int i = 0; i &lt; trustManagers.length; i++) {&lt;br /&gt;               TrustManager trustManager = factory.getTrustManagers()[i];&lt;br /&gt;               if (trustManager instanceof X509TrustManager) {&lt;br /&gt;                   delegate = (X509TrustManager) trustManager;&lt;br /&gt;                   break;&lt;br /&gt;               }&lt;br /&gt;           }&lt;br /&gt;       }&lt;br /&gt;       if (delegate == null) {&lt;br /&gt;           throw new CertificateException(&quot;Cannot found any instance of X509TrustManager&quot;);&lt;br /&gt;       }&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public X509Certificate[] getAcceptedIssuers() {&lt;br /&gt;    if (delegate == null) {&lt;br /&gt;        return null;&lt;br /&gt;    } else {&lt;br /&gt;        return delegate.getAcceptedIssuers();&lt;br /&gt;    }&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public void checkClientTrusted(final X509Certificate[] c, final String a)&lt;br /&gt;                   throws CertificateException {&lt;br /&gt;       if (delegate != null) {&lt;br /&gt;        delegate.checkClientTrusted(c, a);&lt;br /&gt;       } else {&lt;br /&gt;        throw new CertificateException(&quot;Unable to validate this certificate (delegate is null).&quot;);&lt;br /&gt;       }&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public void checkServerTrusted(final X509Certificate[] c, final String a)&lt;br /&gt;                   throws CertificateException {&lt;br /&gt;    if (delegate != null) {&lt;br /&gt;           // hardcoding test to be sure we are trying to validate the right certificate&lt;br /&gt;           if (c.length == 3 &amp;amp;&amp;amp; c[0].getSerialNumber().toString(16).equals(BADCERTIFICATESIGNATURE)) {&lt;br /&gt;            c = new X509Certificate[] {c[0], c[1]};&lt;br /&gt;           }&lt;br /&gt;           delegate.checkServerTrusted(c, a);&lt;br /&gt;    } else {&lt;br /&gt;        throw new CertificateException(&quot;Unable to validate this certificate (delegate is null).&quot;);&lt;br /&gt;    }&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   private static final String BADCERTIFICATESIGNATURE = &quot;xxxxxxxxxxxxxxxxxxxx&quot;;&lt;br /&gt;}&lt;/pre&gt;With this implementation I&#39;m sure that the my invalid certificate will continue to work, and it cannot be faked (as it could be with a completely blind TrustManager). But I can also expect that when the provider will update its certificate, everything will continue to work as expected because all other certificates are still validate the regular way.</content><link rel='replies' type='application/atom+xml' href='http://benoitperroud.blogspot.com/feeds/2225593076371054313/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/5001452664427688683/2225593076371054313' title='7 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5001452664427688683/posts/default/2225593076371054313'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5001452664427688683/posts/default/2225593076371054313'/><link rel='alternate' type='text/html' href='http://benoitperroud.blogspot.com/2010/08/dealing-with-old-ssl-certificats.html' title='Dealing with old SSL certificats (algorithm check failed: MD2withRSA is disabled)'/><author><name>KillerWhile</name><uri>http://www.blogger.com/profile/17113505481300913194</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://www.noisette.ch/wiki/images/Raquette18.jpg'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5001452664427688683.post-2424164447573821741</id><published>2010-08-02T08:53:00.003+02:00</published><updated>2010-08-10T12:33:45.580+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="development"/><category scheme="http://www.blogger.com/atom/ns#" term="java"/><category scheme="http://www.blogger.com/atom/ns#" term="security"/><category scheme="http://www.blogger.com/atom/ns#" term="ssl"/><title type='text'>Java and certificate&#39;s mess : blind SSL factory for commons httpClient</title><content type='html'>There are parts of Java which are not very &quot;quick development&quot; oriented. The side I want to illustrate here is dealing with SSL.&lt;br /&gt;&lt;br /&gt;When the application is in early development stage, we don&#39;t want to bother with stuff like valid certificate. We don&#39;t want to get stuck for days because we haven&#39;t received valid development SSL certificate from Verisign or other &quot;&lt;span style=&quot;font-style: italic;&quot;&gt;more trusted than me&lt;/span&gt;&quot; monopoles. We  just want to activate the &quot;&lt;span style=&quot;font-style: italic;&quot;&gt;--no-check-certificate&lt;/span&gt;&quot; à la &lt;span style=&quot;font-style: italic;&quot;&gt;wget&lt;/span&gt;, or &quot;&lt;span style=&quot;font-style: italic;&quot;&gt;CURLOPT_SSL_VERIFYPEER&lt;/span&gt;&quot; à la &lt;span style=&quot;font-style: italic;&quot;&gt;PHP&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Adding a new certificate in the cacert file is not so complicated, but it is not always possible on every computers (should developers have administrators rights on their computers ?), or break the debian pakage integrity and risk to be overridden at the next &lt;span style=&quot;font-style: italic;&quot;&gt;JRE&lt;/span&gt; update.&lt;br /&gt;&lt;br /&gt;No, for development phase, a &lt;span style=&quot;font-weight: bold;&quot;&gt;blind SSL factory&lt;/span&gt; is a good point for productivity. Simply &lt;span style=&quot;font-weight: bold;&quot;&gt;DO NOT FORGET TO REMOVE IT&lt;/span&gt; in the integration or pre-production phase. Having valid and trusted SSL certificate in production is NOT an optional thing.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size:180%;&quot;&gt;What is a blind SSL factory&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;A blind SSL factory is simply an SSL factory which will validate any certificate. Expirated, selfsigned, but also man-in-the-middled or forged certificates will be trusted.&lt;br /&gt;&lt;br /&gt;Mike McKinney already explained &lt;a href=&quot;http://blog.platinumsolutions.com/node/79&quot;&gt;how to create a blind SSL factory for LDAP connexions&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;I will leverage his explanations to enable blind SSL factory for &lt;a href=&quot;http://hc.apache.org/&quot;&gt;commons httpClient&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;The start point is to create a &lt;span style=&quot;font-style: italic;&quot;&gt;TrustManager&lt;/span&gt; which will trust any certificate, and then give this &lt;span style=&quot;font-style: italic;&quot;&gt;TrustManager&lt;/span&gt; to the SSL factory. This will result in a blind SSL factory :)&lt;br /&gt;&lt;br /&gt;Anonymous class that implements &lt;span style=&quot;font-style: italic;&quot;&gt;X509TrustManager&lt;/span&gt; :&lt;br /&gt;&lt;pre&gt;class BlindX509TrustManager implements X509TrustManager&lt;br /&gt;{&lt;br /&gt;   public X509Certificate[] getAcceptedIssuers()&lt;br /&gt;   {&lt;br /&gt;       return null;&lt;br /&gt;   }&lt;br /&gt;   public void checkClientTrusted(final X509Certificate[] c, final String a)&lt;br /&gt;   {&lt;br /&gt;   }&lt;br /&gt;   public void checkServerTrusted(final X509Certificate[] c, final String a)&lt;br /&gt;   {&lt;br /&gt;   }&lt;br /&gt;}&lt;/pre&gt;Initializing the &lt;span style=&quot;font-style: italic;&quot;&gt;SSLContext&lt;/span&gt; to retrieve a &lt;span style=&quot;font-style: italic;&quot;&gt;SocketFactory&lt;/span&gt; :&lt;br /&gt;&lt;pre&gt;SSLContext sc = SSLContext.getInstance(&quot;SSL&quot;);&lt;br /&gt;sc.init(null, new TrustManager[] { new BlindX509TrustManager() }, new java.security.SecureRandom());&lt;br /&gt;SocketFactory blindFactory = sc.getSocketFactory();&lt;br /&gt;&lt;/pre&gt;And finally the &lt;span style=&quot;font-style: italic;&quot;&gt;BlindSSLProtocolSocketFactory&lt;/span&gt; which implements the needed &lt;span style=&quot;font-style: italic; font-weight: bold;&quot;&gt;ProtocolSocketFactory&lt;/span&gt; of &lt;span style=&quot;font-style: italic;&quot;&gt;httpClient&lt;/span&gt; :&lt;br /&gt;&lt;pre&gt;public class BlindSSLProtocolSocketFactory implements SecureProtocolSocketFactory&lt;br /&gt;{&lt;br /&gt;   public Socket createSocket(String host, int port, InetAddress clientHost, int clientPort) throws IOException,&lt;br /&gt;       UnknownHostException&lt;br /&gt;   {&lt;br /&gt;       return blindFactory.createSocket(host, port, clientHost, clientPort);&lt;br /&gt;   }&lt;br /&gt;   public Socket createSocket(String host, int port, InetAddress localAddress, int localPort, HttpConnectionParams params)&lt;br /&gt;       throws IOException, UnknownHostException, ConnectTimeoutException&lt;br /&gt;   {&lt;br /&gt;       if (params == null)&lt;br /&gt;       {&lt;br /&gt;           throw new IllegalArgumentException(&quot;Parameters may not be null&quot;);&lt;br /&gt;       }&lt;br /&gt;       int timeout = params.getConnectionTimeout();&lt;br /&gt;       if (timeout == 0)&lt;br /&gt;       {&lt;br /&gt;           return createSocket(host, port, localAddress, localPort);&lt;br /&gt;       }&lt;br /&gt;       else&lt;br /&gt;       {&lt;br /&gt;           return ControllerThreadSocketFactory.createSocket(this, host, port, localAddress, localPort, timeout);&lt;br /&gt;       }&lt;br /&gt;   }&lt;br /&gt;   public Socket createSocket(String host, int port) throws IOException, UnknownHostException&lt;br /&gt;   {&lt;br /&gt;       return blindFactory.createSocket(host, port);&lt;br /&gt;   }&lt;br /&gt;   public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException, UnknownHostException&lt;br /&gt;   {&lt;br /&gt;       return ((SSLSocketFactory) blindFactory).createSocket(socket, host, port, autoClose);&lt;br /&gt;   }&lt;br /&gt;   public boolean equals(Object obj)&lt;br /&gt;   {&lt;br /&gt;       return obj != null &amp;amp;&amp;amp; obj.getClass().equals(getClass());&lt;br /&gt;   }&lt;br /&gt;   public int hashCode()&lt;br /&gt;   {&lt;br /&gt;       return getClass().hashCode();&lt;br /&gt;   }&lt;br /&gt;}&lt;/pre&gt;Everything tied up together, put into the classpath of the application, will override the https protocol with the &lt;span style=&quot;font-style: italic;&quot;&gt;BlindSSLProtocolSocketFactory&lt;/span&gt; and thus allow your code to connect any certificate !&lt;br /&gt;&lt;pre&gt;public class BlindSSLProtocolSocketFactory implements SecureProtocolSocketFactory&lt;br /&gt;{&lt;br /&gt; private static final Log LOG = LogFactory.getLog(BlindSSLProtocolSocketFactory.class);&lt;br /&gt; public BlindSSLProtocolSocketFactory()&lt;br /&gt; {&lt;br /&gt;     blindFactory = createBlindSocketFactory();&lt;br /&gt; }&lt;br /&gt; public Socket createSocket(String host, int port, InetAddress clientHost, int clientPort) throws IOException,&lt;br /&gt;         UnknownHostException&lt;br /&gt; {&lt;br /&gt;     return blindFactory.createSocket(host, port, clientHost, clientPort);&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public Socket createSocket(String host, int port, InetAddress localAddress, int localPort, HttpConnectionParams params)&lt;br /&gt;         throws IOException, UnknownHostException, ConnectTimeoutException&lt;br /&gt; {&lt;br /&gt;     if (params == null)&lt;br /&gt;     {&lt;br /&gt;         throw new IllegalArgumentException(&quot;Parameters may not be null&quot;);&lt;br /&gt;     }&lt;br /&gt;     int timeout = params.getConnectionTimeout();&lt;br /&gt;     if (timeout == 0)&lt;br /&gt;     {&lt;br /&gt;         return createSocket(host, port, localAddress, localPort);&lt;br /&gt;     }&lt;br /&gt;     else&lt;br /&gt;     {&lt;br /&gt;         return ControllerThreadSocketFactory.createSocket(this, host, port, localAddress, localPort, timeout);&lt;br /&gt;     }&lt;br /&gt; }&lt;br /&gt; public Socket createSocket(String host, int port) throws IOException, UnknownHostException&lt;br /&gt; {&lt;br /&gt;     return blindFactory.createSocket(host, port);&lt;br /&gt; }&lt;br /&gt; public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException, UnknownHostException&lt;br /&gt; {&lt;br /&gt;     return ((SSLSocketFactory) blindFactory).createSocket(socket, host, port, autoClose);&lt;br /&gt; }&lt;br /&gt; public boolean equals(Object obj)&lt;br /&gt; {&lt;br /&gt;     return obj != null &amp;amp;&amp;amp; obj.getClass().equals(getClass());&lt;br /&gt; }&lt;br /&gt; public int hashCode()&lt;br /&gt; {&lt;br /&gt;     return getClass().hashCode();&lt;br /&gt; }&lt;br /&gt; private SocketFactory blindFactory = null;&lt;br /&gt; private static SocketFactory createBlindSocketFactory()&lt;br /&gt; {&lt;br /&gt;     try&lt;br /&gt;     {&lt;br /&gt;         SSLContext context = SSLContext.getInstance(&quot;SSL&quot;);&lt;br /&gt;         context.init(null, new TrustManager[] { new BlindX509TrustManager() }, null);&lt;br /&gt;         return context.getSocketFactory();&lt;br /&gt;     }&lt;br /&gt;     catch (Exception e)&lt;br /&gt;     {&lt;br /&gt;         LOG.error(e.getMessage(), e);&lt;br /&gt;         throw new HttpClientError(e.toString());&lt;br /&gt;     }&lt;br /&gt; }&lt;br /&gt;}&lt;/pre&gt;And to regirster the new protocol as the default https protocol :&lt;br /&gt;&lt;pre style=&quot;font-weight: bold;&quot;&gt;Protocol.registerProtocol(&quot;https&quot;, new Protocol(&quot;https&quot;, (ProtocolSocketFactory) new BlindSSLProtocolSocketFactory(), 443));&lt;/pre&gt;&lt;br /&gt;Please note that if you want only access a selfsigned certificate you have better to use &lt;a href=&quot;http://svn.apache.org/viewvc/httpcomponents/oac.hc3x/trunk/src/contrib/org/apache/commons/httpclient/contrib/ssl/EasySSLProtocolSocketFactory.java&quot;&gt;&lt;span style=&quot;font-style: italic;&quot;&gt;EasySSLProtocolSocketFactory&lt;/span&gt;&lt;/a&gt; from &lt;span style=&quot;font-style: italic;&quot;&gt;httpClient contibs&lt;/span&gt;. It still validate the selfsigned certificate, so expired or bad certificate will be denied.</content><link rel='replies' type='application/atom+xml' href='http://benoitperroud.blogspot.com/feeds/2424164447573821741/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/5001452664427688683/2424164447573821741' title='2 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5001452664427688683/posts/default/2424164447573821741'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5001452664427688683/posts/default/2424164447573821741'/><link rel='alternate' type='text/html' href='http://benoitperroud.blogspot.com/2010/08/java-and-certificates-mess-blind-ssl.html' title='Java and certificate&#39;s mess : blind SSL factory for commons httpClient'/><author><name>KillerWhile</name><uri>http://www.blogger.com/profile/17113505481300913194</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://www.noisette.ch/wiki/images/Raquette18.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5001452664427688683.post-2383658379882692325</id><published>2010-04-25T10:30:00.001+02:00</published><updated>2010-04-25T10:44:26.203+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="concurrent"/><category scheme="http://www.blogger.com/atom/ns#" term="doodle clone"/><category scheme="http://www.blogger.com/atom/ns#" term="nosql"/><title type='text'>Implementing unique constraints with Cassandra</title><content type='html'>I was talking about my &quot;&lt;a href=&quot;http://doodle.noisette.ch/&quot;&gt;Doodle clone with Cassandra backend&lt;/a&gt;&quot; in a &lt;a href=&quot;http://benoitperroud.blogspot.com/2010/04/doodle-clone-with-cassandra-backend.html&quot;&gt;previous post&lt;/a&gt;, I want to explain a little bit how I implement 2 kinds of constraints with Cassandra.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size:130%;&quot;&gt;Unique name constrain&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;When subscribing to a poll, a unique constraint on the name of the subscriber is applied. There is a first check in Javascript in the GUI, but there is also a check of the uniqueness of the names on the server side.&lt;br /&gt;&lt;br /&gt;Before going deeper, I just need to say a word about the structure used :&lt;br /&gt;&lt;br /&gt;To store the subscribers, I use a SuperColumnFamily, with the ID of the poll as key. For a poll having key &quot;1234&quot;, it gives me something like :&lt;br /&gt;&lt;blockquote style=&quot;font-style: italic;&quot;&gt;&quot;1234&quot; =&gt; {&lt;br /&gt;   &quot;subscriberKey1&quot; =&gt; { name = &quot;subscriberName1&quot;, options = ... }&lt;br /&gt;   &quot;subscriberKey2&quot; =&gt; { name = &quot;subscriberName2&quot;, options = ... }&lt;br /&gt;   ...&lt;br /&gt;}&lt;/blockquote&gt;The trick about the &lt;span style=&quot;font-style: italic;&quot;&gt;subscriberKey*&lt;/span&gt; is to generate a unique ID based on a timestamp in order to be sorted by Cassandra.&lt;br /&gt;The key will be something like : currentTimestamp - ClusterNodeId - ThreadId. Adding the ThreadId into the key give me the guarantee that using the System.currentTimeMillis() will be unique, because the processing will unfortunately take more than a millisecond :)&lt;br /&gt;&lt;br /&gt;Using this key, I will write the subscriber row with ConsistencyLevel.QUORUM, and then I will read all the rows till the one I have inserted (with ConsistencyLevel.QUORUM again).&lt;br /&gt;At this point I use Cassandra magic (rows are ordered) to be sure that I have selected all the subscribers they subscribe &lt;span style=&quot;font-weight: bold;&quot;&gt;before&lt;/span&gt; the current one.&lt;br /&gt;I remains me to check manually the uniqueness of the name. If another row has the same name, I will simply remove the current subscriber.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size:130%;&quot;&gt;Limiting the number of subscribers per option&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Another constraint I have implemented is the limitation of the number of subscribers per option.&lt;br /&gt;&lt;br /&gt;The principle is the same as the unique name constraint : I count the number of previously inserted subscriber.&lt;br /&gt;One point to keep in mind is that we can read a row with a duplicated name, which will be deleted later so it should not be taken into account for the actual constraint. This mean that we need to check if we are not counting duplicated names in this constraint too...&lt;br /&gt;&lt;br /&gt;But the good news about this constraint is that it show a way to implement counters in Cassandra. Maybe I will write another post about this topic. The bad news is that we need to check the duplicated names in several places.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size:130%;&quot;&gt;Limitation of the model&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;Complexity&lt;/span&gt; : adding more constraints grows the complexity in  O(n^2), as every new constraints (duplicated names) should be implemented into every other constraints (limitation of subscribers per option).&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;Scalability&lt;/span&gt; : this model will scale very well for billions of polls with some tens of users. The inverse, some tens of polls with billions of users, needs a lot of resources for checking constraint, which will make the performance drop.</content><link rel='replies' type='application/atom+xml' href='http://benoitperroud.blogspot.com/feeds/2383658379882692325/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/5001452664427688683/2383658379882692325' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5001452664427688683/posts/default/2383658379882692325'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5001452664427688683/posts/default/2383658379882692325'/><link rel='alternate' type='text/html' href='http://benoitperroud.blogspot.com/2010/04/implementing-unique-constraints-with.html' title='Implementing unique constraints with Cassandra'/><author><name>KillerWhile</name><uri>http://www.blogger.com/profile/17113505481300913194</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://www.noisette.ch/wiki/images/Raquette18.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5001452664427688683.post-7432546396050489918</id><published>2010-04-24T19:45:00.003+02:00</published><updated>2010-04-24T20:29:47.183+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="doodle clone"/><category scheme="http://www.blogger.com/atom/ns#" term="nosql"/><title type='text'>Doodle clone with Cassandra backend</title><content type='html'>I follow &lt;a href=&quot;http://cassandra.apache.org&quot;&gt;Cassandra&lt;/a&gt;&#39;s activity for some months now, and I decided to try it. But what better than developing a small application to test real needs ?&lt;br /&gt;&lt;br /&gt;That&#39;s what I did with my &quot;&lt;a href=&quot;http://doodle.noisette.ch&quot;&gt;Doodle clone with Cassandra backend&lt;/a&gt;&quot;.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size:130%;&quot;&gt;What is Cassandra ?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;According to the main page,&lt;br /&gt;&lt;blockquote style=&quot;font-style: italic;&quot;&gt;Cassandra is a highly scalable, eventually consistent, distributed, structured key-value store&lt;/blockquote&gt;&lt;span style=&quot;font-size:130%;&quot;&gt;Why a Doodle clone ?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I&#39;m working during my free time on an &lt;a href=&quot;http://www.groople.ch&quot;&gt;event manager&lt;/a&gt; software, so it was a good pretext to analyze Doodle business :)&lt;br /&gt;It appears to be quite simple, so it was a good starting point.&lt;br /&gt;&lt;span style=&quot;display: block;&quot; id=&quot;formatbar_Buttons&quot;&gt;&lt;span class=&quot; on down&quot; style=&quot;display: block;&quot; id=&quot;formatbar_CreateLink&quot; title=&quot;Lien&quot; onmouseover=&quot;ButtonHoverOn(this);&quot; onmouseout=&quot;ButtonHoverOff(this);&quot; onmouseup=&quot;&quot; onmousedown=&quot;CheckFormatting(event);FormatbarButton(&#39;richeditorframe&#39;, this, 8);ButtonMouseDown(this);&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-size:130%;&quot;&gt;Which features to implement ?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I added the following feature to the doodle clone :&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Easy (easier) to create polls&lt;/li&gt;&lt;li&gt;Login free, secret key based administration &lt;/li&gt;&lt;li&gt;No options limitation&lt;/li&gt;&lt;li&gt;Email feedback when someone subscribe the poll (if email provided)&lt;br /&gt;&lt;/li&gt;&lt;li&gt;No duplicate name of the subscribers&lt;/li&gt;&lt;li&gt;An optional limitation of the number of subscribers per options&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style=&quot;font-size:130%;&quot;&gt;Have a look&lt;/span&gt; !&lt;br /&gt;&lt;br /&gt;Go to &lt;a href=&quot;http://doodle.noisette.ch&quot;&gt;http://doodle.noisette.ch&lt;/a&gt; and try it, the result is really surprising.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size:130%;&quot;&gt;Disclaimer&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; There is absolutely no affiliation with Doodle, neither any idea to become the next Doodle. The goal of this application is purely academic, and it is deployed as is, without any guarantee.&lt;span style=&quot;display: block;&quot; id=&quot;formatbar_Buttons&quot;&gt;&lt;span class=&quot; on down&quot; style=&quot;display: block;&quot; id=&quot;formatbar_CreateLink&quot; title=&quot;Lien&quot; onmouseover=&quot;ButtonHoverOn(this);&quot; onmouseout=&quot;ButtonHoverOff(this);&quot; onmouseup=&quot;&quot; onmousedown=&quot;CheckFormatting(event);FormatbarButton(&#39;richeditorframe&#39;, this, 8);ButtonMouseDown(this);&quot;&gt;&lt;/span&gt;&lt;/span&gt;</content><link rel='replies' type='application/atom+xml' href='http://benoitperroud.blogspot.com/feeds/7432546396050489918/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/5001452664427688683/7432546396050489918' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5001452664427688683/posts/default/7432546396050489918'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5001452664427688683/posts/default/7432546396050489918'/><link rel='alternate' type='text/html' href='http://benoitperroud.blogspot.com/2010/04/doodle-clone-with-cassandra-backend.html' title='Doodle clone with Cassandra backend'/><author><name>KillerWhile</name><uri>http://www.blogger.com/profile/17113505481300913194</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://www.noisette.ch/wiki/images/Raquette18.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5001452664427688683.post-8967207462857223988</id><published>2010-04-05T13:13:00.004+02:00</published><updated>2010-04-05T13:22:02.803+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="nosql"/><title type='text'>Don&#39;t be abused by the term &quot;commodity hardware&quot;</title><content type='html'>&lt;a href=&quot;http://en.wikipedia.org/wiki/NoSQL&quot;&gt;NoSQL paradigm&lt;/a&gt; claims to build clusters of &quot;commodity hardware&quot;. But don&#39;t be abused by this term : &quot;commodity hardware&quot; is not your living room&#39;s computer. Commodity hardware is two slots&#39; computer, 16+GB RAM, (ten)giga ethernet, raid5 hard disks.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Commodity hardware is not 500$ computers. It&#39;s 5000$ computers. But building a 10 nodes&#39; cluster for 50&#39;000$ is still really cheap.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;And remeber : clusters&#39; primary bottlneck is I/O. Both disk and network. So there is no place for virtualisation here.&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://benoitperroud.blogspot.com/feeds/8967207462857223988/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/5001452664427688683/8967207462857223988' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5001452664427688683/posts/default/8967207462857223988'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5001452664427688683/posts/default/8967207462857223988'/><link rel='alternate' type='text/html' href='http://benoitperroud.blogspot.com/2010/04/dont-be-abused-by-term-commodity.html' title='Don&#39;t be abused by the term &quot;commodity hardware&quot;'/><author><name>KillerWhile</name><uri>http://www.blogger.com/profile/17113505481300913194</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://www.noisette.ch/wiki/images/Raquette18.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5001452664427688683.post-664568960075243033</id><published>2009-12-30T11:46:00.007+01:00</published><updated>2009-12-31T19:23:00.726+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="algorithm"/><category scheme="http://www.blogger.com/atom/ns#" term="concurrent"/><category scheme="http://www.blogger.com/atom/ns#" term="scalability"/><title type='text'>Sequences scalability</title><content type='html'>Sequences are central part of most computer systems. They are used both in technical part (generate unique identifier for object) and in business part (count the remaining free tickets which can be sold).&lt;br /&gt;&lt;br /&gt;When the load on the application goes higher, sequences become quickly central bottlenecks of systems. So the goal here is to first categorize different types of sequences and then gives some keys to see how sequences be distributed to increase their scalability, and hence the global scalability of the whole system.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size:130%;&quot;&gt;Characteristics of sequences : &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;Order&lt;/span&gt; : the number generate should be used in a given order (ascendant or descendant), or the order do not matter. I will talk about &lt;span style=&quot;font-style: italic;&quot;&gt;ordered&lt;/span&gt; or &lt;span style=&quot;font-style: italic;&quot;&gt;unordered&lt;/span&gt; sequence.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;Missing values&lt;/span&gt; : some values can be missing in the sequence. For example the sequence miss the value 4 should not alter the behavior of the application. I will talk about &lt;span style=&quot;font-style: italic;&quot;&gt;continued&lt;/span&gt; or &lt;span style=&quot;font-style: italic;&quot;&gt;discontinued&lt;/span&gt; sequence.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;Finite sequence&lt;/span&gt; : all the values of the sequence are know and countable. Countable sequences are particular case of finite sequence where the sequence has a reasonable amount of values, and thus could be represented by one object per values. I will talk about &lt;span style=&quot;font-style: italic;&quot;&gt;finite&lt;/span&gt; or &lt;span style=&quot;font-style: italic;&quot;&gt;infinite&lt;/span&gt; sequence, and &lt;span style=&quot;font-style: italic;&quot;&gt; countable&lt;/span&gt; sequence.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size:130%;&quot;&gt;Key to distribute sequences&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Discontinued sequences are easy to scale : the application can pick numbers n by n in the sequence, reducing the amount of calls to the sequence by n. Good example for of discontinued sequences are   objects identifier generators.&lt;br /&gt;&lt;br /&gt;Unordered sequences are also easy to scale : a counter can be decomposed in n subcounter, picking at random one of the subcounter to increment or decrement will reduce the contention on one counter by n. A typical example is a quantity of object to sell. N subcounters are initialized with the sum is the total amount to sell. The object cannot be sold anymore when every subcounters are at 0.&lt;br /&gt;&lt;br /&gt;Countable sequences can be scaled by representing every value of the sequence as a single object in the database. Updating an unused object is a easy task.&lt;br /&gt;&lt;br /&gt;Finaly infinite, continued ordered sequence are very hard to scale because synchronization between all callers is required, so a single point of contention is mandatory.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size:130%;&quot;&gt;Conclusion&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Sequences are choke point in most systems, but as we saw above they can scale relatively simply with two simple tricks : read number n by n instead of 1 by 1, or decompose a counter in n subcounters.</content><link rel='replies' type='application/atom+xml' href='http://benoitperroud.blogspot.com/feeds/664568960075243033/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/5001452664427688683/664568960075243033' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5001452664427688683/posts/default/664568960075243033'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5001452664427688683/posts/default/664568960075243033'/><link rel='alternate' type='text/html' href='http://benoitperroud.blogspot.com/2009/12/sequences-scalability.html' title='Sequences scalability'/><author><name>KillerWhile</name><uri>http://www.blogger.com/profile/17113505481300913194</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://www.noisette.ch/wiki/images/Raquette18.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5001452664427688683.post-5866650845037124965</id><published>2009-11-15T20:44:00.006+01:00</published><updated>2009-11-15T21:46:16.628+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="concurrent"/><category scheme="http://www.blogger.com/atom/ns#" term="development"/><category scheme="http://www.blogger.com/atom/ns#" term="java"/><title type='text'>Call different services, use the first to reply</title><content type='html'>&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-size: x-large;&quot;&gt;The needs&lt;/span&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;My needs were the following : I have an arbitrary amount of &lt;i&gt;webservices&lt;/i&gt; to call, but I don&#39;t know, for a particular query, which one will return the answer. More than that, some are slower and others are faster, but again, I don&#39;t know which is the fastest for my particular query.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So what I will do is to parallelize the queries, and use the value of the first which return my a good value.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-size: x-large;&quot;&gt;Use an Executor&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The first component to implement such a requirement is an &lt;i&gt;Executor&lt;/i&gt;.&lt;/div&gt;&lt;div&gt;The &lt;i&gt;Executor&lt;/i&gt; will run all my queries, in as many threads as I want, permitting to fine tune the behavior of the system.&lt;/div&gt;&lt;div&gt;As many queries will input the system and will be translated in many more threads, it is important to use a limited amount of threads to not crash the system.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot;&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-size: x-large;&quot;&gt;Synchronization on result&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;A specific object will be used to synchronize the result : the first result will be returned to the caller, letting the running threads die, and no more threads will be run for this query.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Some basic primitive for concurrent programming (&lt;i&gt;java.util.concurrent&lt;/i&gt;) will be used, such as &lt;i&gt;CountDownLatch&lt;/i&gt; : the caller will block on the latch, and once a thread will find the answer, it will set the value into the result and count down the latch. The caller will be freed and the value will be available.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-size: x-large;&quot;&gt;Watchdog if all the queries fail&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;One point to not forget is if every queries fail, the caller should be informed of this fail.&lt;/div&gt;&lt;div&gt;A watchdog will be used : it will block till all the threads executing the query will finish, and will then be run. Its only task is to free the caller. This one will continue the processing, but the result will not be available. This will be the responsibility of the caller to run user code to handle this special case.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-size: x-large;&quot;&gt;Strong requirements&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The requirements are the following : &lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;Use as little synchronization as possible&lt;/li&gt;&lt;li&gt;Use as much concurrent primitives (&lt;i&gt;java.util.concurrent&lt;/i&gt;) as possible&lt;/li&gt;&lt;li&gt;Do it as generic as possible&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-size: x-large;&quot;&gt;Java implementation&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The interesting part of the implementation is given here below.&lt;/div&gt;&lt;div&gt;The Executor is simply an java.util.concurrent.Executor. I&#39;m not good enough to implement a better solution than they do.&lt;/div&gt;&lt;div&gt;The result object is composed of the following attributes :&lt;/div&gt;&lt;div&gt;&lt;blockquote&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;public class FutureResult&lt;t&gt; {&lt;/t&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt; &lt;/span&gt;private T result;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt; &lt;/span&gt;private boolean done;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt; &lt;/span&gt;private AtomicInteger threadCount = new AtomicInteger(0);&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt; &lt;/span&gt;private CountDownLatch latch = new CountDownLatch(1);&lt;/div&gt;&lt;div&gt;}&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;A generic type for the value, a &lt;i&gt;AtomicInteger&lt;/i&gt; to count how many other threads are working on this result, and a latch to make the caller wait.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The watchdog class will simply wait till all the threads are finish and free the caller if it is not already the case :&lt;/div&gt;&lt;div&gt;&lt;blockquote&gt;&lt;/blockquote&gt;&lt;span&gt;&lt;span&gt;&lt;blockquote&gt;&lt;/blockquote&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;class WatchDogRunnable implements Runnable {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;div&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre; &quot;&gt; &lt;/span&gt;public void run() {&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt; &lt;/span&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre; &quot;&gt; &lt;/span&gt;while (result.hasThreadsWorking()) {&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt;   &lt;/span&gt;synchronized (result) {&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt;    &lt;/span&gt;result.wait(2000);&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt;   &lt;/span&gt;}&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt;  &lt;/span&gt;}&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt;  &lt;/span&gt;latch.countDown();&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt; &lt;/span&gt;}&lt;/div&gt;&lt;div&gt;}&lt;/div&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;div&gt;&lt;/div&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;And finally an abstract callable worker which can be easily extended to run the wanted tasks. The call function will increment the &lt;i&gt;AtomicInteger&lt;/i&gt;, do the work if it is not already done, if a result is found, free the caller, decrement the &lt;i&gt;AtomicInteger&lt;/i&gt; and return the value if it is set. Not that the worker implementation will implement the callInternal function.&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;public abstract class AbstractCallableWorker&lt;t&gt;&lt;br /&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre; &quot;&gt; &lt;/span&gt;implements Callable&lt;t&gt; {&lt;/t&gt;&lt;/t&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt; &lt;/span&gt;private FutureResult&lt;t&gt; result;&lt;/t&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt; &lt;/span&gt;public final T call() {&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt;  &lt;/span&gt;result.setOneMoreThread();&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt;  &lt;/span&gt;if (!result.isDone()) {&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt;   &lt;/span&gt;T callResult = callInternal();&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt;   &lt;/span&gt;if (callResult != null) {&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt;    &lt;/span&gt;setResult(callResult);&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt;    &lt;/span&gt;latch.countDown();&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt;   &lt;/span&gt;}&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt;  &lt;/span&gt;}&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt;  &lt;/span&gt;result.setOneLessWorkingThead();&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt;  &lt;/span&gt;return result.getResult();&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt; &lt;/span&gt;}&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt; &lt;/span&gt;protected abstract T callInternal();&lt;/div&gt;&lt;div&gt;}&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;Everything put together, you can implement as much worker as you want and call as many &lt;i&gt;webservice&lt;/i&gt; as you want, with the only guaranty to get the caller continue with the fastest service to reply !&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://benoitperroud.blogspot.com/feeds/5866650845037124965/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/5001452664427688683/5866650845037124965' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5001452664427688683/posts/default/5866650845037124965'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5001452664427688683/posts/default/5866650845037124965'/><link rel='alternate' type='text/html' href='http://benoitperroud.blogspot.com/2009/11/call-different-services-use-first-to.html' title='Call different services, use the first to reply'/><author><name>KillerWhile</name><uri>http://www.blogger.com/profile/17113505481300913194</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://www.noisette.ch/wiki/images/Raquette18.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5001452664427688683.post-1954780904409640287</id><published>2009-11-14T21:36:00.004+01:00</published><updated>2009-11-14T22:12:02.625+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="apache"/><category scheme="http://www.blogger.com/atom/ns#" term="cluster"/><category scheme="http://www.blogger.com/atom/ns#" term="j2ee"/><category scheme="http://www.blogger.com/atom/ns#" term="opensource"/><title type='text'>Clustering Jackrabbit 1.5.x with DataStore configuration</title><content type='html'>&lt;a href=&quot;http://jackrabbit.apache.org/&quot;&gt;&lt;blockquote&gt;&lt;/blockquote&gt;Jackrabbit&lt;/a&gt; is the reference implementation of JSR-170 : JCR, Java Content Repository.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;One day we felt the needs to run a Jackrabbit repository in a clustered environment for reliability. So a JCR runs on two separated servers, backed by the an Oracle db and a NFS shared datastore.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhMjplRuPpDHyBROI2-0IrWnduaxdxiG1jyy7iF6OlkFW6hdS5gkkVCB998yE0t0nUfUvu62fHwROK8fRIKX6ZOtg19gZelAToC9yUolA-qAn131nbOPkly-yzMrxIhC3XC71iB0lf6WvZk/s1600-h/jcr-cluster.png&quot;&gt;&lt;img src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhMjplRuPpDHyBROI2-0IrWnduaxdxiG1jyy7iF6OlkFW6hdS5gkkVCB998yE0t0nUfUvu62fHwROK8fRIKX6ZOtg19gZelAToC9yUolA-qAn131nbOPkly-yzMrxIhC3XC71iB0lf6WvZk/s400/jcr-cluster.png&quot; border=&quot;0&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5404064434849354082&quot; style=&quot;cursor: pointer; width: 400px; height: 176px; &quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;It exists some difficulties to run such architecture, mainly because both JCR nodes (JCR1 and JCR2) do not know each others. So if we insert some content on one node, it takes some time before we can read it on the other node.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;In Jackrabbit&lt;span&gt;&lt;span&gt; 1.5.x, &lt;i&gt;Session.refresh&lt;/i&gt; do not work correctly, s&lt;/span&gt;&lt;/span&gt;o we need to do some trick to enable cluster (synchronization) features.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;First of all, we add a custom &lt;i&gt;ServletFilter&lt;/i&gt; which handle the GET (read) request and transform it on a HEAD one (test if the content exists) using &lt;i&gt;apache.commons.HttpClient&lt;/i&gt;.&lt;/div&gt;&lt;div&gt;If the return of the query says the content exists, then we run the normal request. If the content do not exists, we way for some arbitrary time and relaunch the HEAD request.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This filter will let enough time to the node to synchronize itself, and then perform the query in the right way.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Other possibilities like HEAD on the current node and then HEAD on a different node should also be possible, but this will require every nodes to know about every other nodes. No the best idea.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;One another tricky point is to store all the content to the configured datastore. Be carefull to not rely on a JNDI persistence manager, but be sure to use a subclass of a bundle persistence manager, otherwise you will have some surprise with the size of the database.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://benoitperroud.blogspot.com/feeds/1954780904409640287/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/5001452664427688683/1954780904409640287' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5001452664427688683/posts/default/1954780904409640287'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5001452664427688683/posts/default/1954780904409640287'/><link rel='alternate' type='text/html' href='http://benoitperroud.blogspot.com/2009/11/clustering-jackrabbit-15x-with.html' title='Clustering Jackrabbit 1.5.x with DataStore configuration'/><author><name>KillerWhile</name><uri>http://www.blogger.com/profile/17113505481300913194</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://www.noisette.ch/wiki/images/Raquette18.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhMjplRuPpDHyBROI2-0IrWnduaxdxiG1jyy7iF6OlkFW6hdS5gkkVCB998yE0t0nUfUvu62fHwROK8fRIKX6ZOtg19gZelAToC9yUolA-qAn131nbOPkly-yzMrxIhC3XC71iB0lf6WvZk/s72-c/jcr-cluster.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5001452664427688683.post-6209340364235914532</id><published>2009-01-17T18:24:00.007+01:00</published><updated>2011-01-06T12:39:08.538+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="algorithm"/><category scheme="http://www.blogger.com/atom/ns#" term="j2ee"/><category scheme="http://www.blogger.com/atom/ns#" term="security"/><title type='text'>Des nombres à usage unique (nonce)</title><content type='html'>Afin de répondre à une problématique de transmission d&#39;informations sensibles sur un réseau pas sûr (Internet donc...), une solution est l&#39;utilisation de nonce, diminutif de &lt;span style=&quot;font-style: italic;&quot;&gt;number used once&lt;/span&gt;, nombre à usage unique.&lt;br /&gt;&lt;br /&gt;Ils sont utilisé pour mettre du sel dans des informations sensibles qui seront ensuite hashées et transmises en clair sur le réseau. Mais leur efficacité n&#39;est effective seulement si on a la garantie qu&#39;un même nonce ne va jamais être utilisé 2 fois !&lt;br /&gt;&lt;br /&gt;Exemple type : vous développez un service d&#39;authentification, mais celui-ce ne peut se faire sur du SSL. Vous souhaitez toutefois que si une personne intercepte les informations, elle ne puisse pas les réutiliser pour s&#39;identifier à son tour.&lt;br /&gt;&lt;br /&gt;Le seul hashage du mot de passe ne suffisant pas car la personne qui a interceptée le mot de passe hashé pourra rejouer la séquence pour simuler sa connexion, une solution est de hasher le mot de passe concaténé au nonce (du style sha256(&quot;#&quot; + mot de passe + &quot;#&quot; + nonce + &quot;#&quot;)), puis de transmettre le nom d&#39;utilisateur, le nonce utilisé et le résultat du hashage. Le serveur disposera ainsi de toutes les informations pour vérifier si le mot de passe utilisé pour le hashage était effectivement correcte ou pas. Les prochaines requêtes faites avec ce nonce seront systématiquement refusées.&lt;br /&gt;&lt;br /&gt;C&#39;est pour faciliter l&#39;accès à ces nombres que je mets à disposition un petit service de génération de nombre à unique, accessible publiquement à l&#39;adresse&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size:130%;&quot;&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;http://nonce.noisette.ch/next&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Chaque appel à cette url retourne un chaine de 32 caractères composées des lettres a-z, A-Z et les chiffres 0-9. Notez que les chaines retournées sont donc senible à la casse.&lt;br /&gt;&lt;br /&gt;Le nombre de nonce possible est donc (26+26+10)^32 = 2.27 * 10^57, soit à peu près &lt;a href=&quot;http://fr.wikipedia.org/wiki/Nombre_parasite&quot;&gt;6-parasite&lt;/a&gt;, ou beaucoup plus que d&#39;atomes dans l&#39;univers.&lt;br /&gt;&lt;br /&gt;A utiliser sans modération pour toute application nécessitant la transmission d&#39;informations sensibles sur un réseau non sécurisé.&lt;br /&gt;&lt;br /&gt;Edit (06.01.2011) : GAE ne supporte plus le proxying, vous pouvez essayer l&#39;app directement sur &lt;a href=&quot;http://noisette-nonce.appspot.com/&quot;&gt;http://noisette-nonce.appspot.com/&lt;/a&gt;.</content><link rel='replies' type='application/atom+xml' href='http://benoitperroud.blogspot.com/feeds/6209340364235914532/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/5001452664427688683/6209340364235914532' title='2 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5001452664427688683/posts/default/6209340364235914532'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5001452664427688683/posts/default/6209340364235914532'/><link rel='alternate' type='text/html' href='http://benoitperroud.blogspot.com/2009/01/des-nombres-usage-unique-nonce.html' title='Des nombres à usage unique (nonce)'/><author><name>KillerWhile</name><uri>http://www.blogger.com/profile/17113505481300913194</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://www.noisette.ch/wiki/images/Raquette18.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5001452664427688683.post-2925541384205042937</id><published>2008-06-08T20:00:00.000+02:00</published><updated>2008-06-08T20:23:18.737+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="development"/><category scheme="http://www.blogger.com/atom/ns#" term="network"/><category scheme="http://www.blogger.com/atom/ns#" term="proxy"/><category scheme="http://www.blogger.com/atom/ns#" term="security"/><category scheme="http://www.blogger.com/atom/ns#" term="thinking"/><title type='text'>Implémentation d&#39;un serveur proxy HTTP</title><content type='html'>La question à la base de cet article est la suivante :&lt;br /&gt;&lt;blockquote style=&quot;font-weight: bold;&quot;&gt;Comment faire pour que mes concurrents ne soient pas au courant que j&#39;observe (très) régulièrement une section particulière de leur site internet ?&lt;/blockquote&gt;La première étape bien évidemment est de la légitimer cette question. Comment un concurrent pourrait savoir que je consulte régulièrement son site ?&lt;br /&gt;&lt;br /&gt;La réponse est simple. Prenons un cas concret pour illustrer : &lt;a href=&quot;http://www.elca.ch/&quot;&gt;ELCA Informatique&lt;/a&gt; possède les plages d&#39;adresses ips 193.72.144.0 - 193.72.147.255 (bloc /22 = 1024 ips, hosté chez Cablecom) et 193.73.238.0 - 193.73.238.255 (bloc /24 = 256 ips, hosté chez Sunrise)&lt;br /&gt;&lt;br /&gt;Ce genre d&#39;info se trouve très facilement via un mélange &lt;span style=&quot;font-style: italic;&quot;&gt;whois&lt;/span&gt;, &lt;span style=&quot;font-style: italic;&quot;&gt;traceroute&lt;/span&gt; et autres informations DNS.&lt;br /&gt;&lt;br /&gt;Une fois qu&#39;on a ces ips, il suffit de rechercher dans les logs les hits faits par ces ips et on pourra dresser un profil précis des intérêts des collaborateurs d&#39;ELCA sur notre site.&lt;br /&gt;&lt;br /&gt;Donc comment faire pour éviter cette traçabilité ?&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size:130%;&quot;&gt;Connexion Internet à adresse ip dynamique (xDSL)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Une première solution est d&#39;utiliser une connexion xDSL pour toutes les connexions humaines à Internet, et de dédier exclusivement les plages d&#39;ips fixes et repérables aux services de l&#39;entreprise. Cette pratique est de plus en plus courante, surtout avec l&#39;arrivée des connexions VDSL et de boitiers qui permettent d&#39;agréger plusieurs lignes xDSL afin d&#39;une part d&#39;avoir un redondance, et d&#39;autre part de partager la somme des débits des lignes entre les utilisateurs. Le seul détail concernant cette solution est de vérifier que l&#39;adresse ip change réellement, faute de quoi il faudrait forcer ce changement.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size:130%;&quot;&gt;Serveur proxy&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Une autre solution, que je vais détailler ici car elle est plus intéressante d&#39;un point de vue ingénierie informatique, est de faire passer le traffic des utilisateurs par un proxy. Par proxy j&#39;entends tout type de connexion indirect à Internet, donc autant les serveurs proxy HTTP, SOCKS, etc que les réseaux de proxy comme par exemple &lt;a href=&quot;http://fr.wikipedia.org/wiki/Tor_%28r%C3%A9seau%29&quot;&gt;Tor&lt;/a&gt;.&lt;br /&gt;Le fait d&#39;accéder à Internet par l&#39;intermédiaire d&#39;un proxy permet de visualiser un site avec une adresse ip qui n&#39;est pas notre, mais appartient à un prestataire de ce genre de service. Cependant l&#39;anonymité à 100% n&#39;existe pas : il existera toujours un intermédiaire qui saura qui a accédé où. La confiance des intermédiaires est donc de mises dans cette configuration.&lt;br /&gt;&lt;br /&gt;Il existe une grande quantité de serveur proxy logiciel de qualité, open source ou commercial, comme par exemple &lt;a href=&quot;http://www.squid-cache.org/&quot;&gt;Squid&lt;/a&gt;, &lt;a href=&quot;http://www.privoxy.org/&quot;&gt;Privoxy&lt;/a&gt;, &lt;a href=&quot;http://httpd.apache.org/docs/2.2/mod/mod_proxy.html&quot;&gt;Apache mod_proxy&lt;/a&gt;, etc... Mais une fois de plus, l&#39;utilisation d&#39;un logiciel existant nous priverait du plaisir de développer de notre propre implémentation.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size:130%;&quot;&gt;Principe de base&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Le principe d&#39;un serveur proxy est donc d&#39;intercepter la requête d&#39;un navigateur, d&#39;ouvrir une connexion vers le site cible, transmettre la requête original, lire le résultat et finalement renvoyer ce résultat au navigateur.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size:130%;&quot;&gt;Protocole HTTP&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;La partie centrale d&#39;un serveur proxy HTTP réside sa compréhension du protocole HTTP. Celui-ci comporte des particularités qui vont être détaillées.&lt;br /&gt;&lt;br /&gt;Le serveur proxy va recevoir une requête du navigateur, dont la première ligne comporte l&#39;action à exécuter, l&#39;url de la cible et une éventuelle version du protocole utilisé :&lt;br /&gt;&lt;blockquote&gt;GET http://www.noisette.ch/ HTTP/1.0&lt;/blockquote&gt;Cette première ligne va donc directement nous renseigner sur le serveur cible à connecter. Le reste de la requête est composée de lignes de header, contenant diverses informations sur la requête comme le navigateur utilisé ou le &lt;span style=&quot;font-style: italic;&quot;&gt;referer&lt;/span&gt; (en français on dit comment ?).&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;Transfer de la requête au serveur cible&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;La prochaine étape est le transfert de la requête au serveur cible. A ce moment on peut éventuellement modifier ou enlever des headers du client, voir en ajouter d&#39;autres. Plus précisément, il peut être intéressant de filtrer tous les headers des clients qui pourraient trahir l&#39;utilisateur du proxy (&lt;span style=&quot;font-style: italic;&quot;&gt;information leakage&lt;/span&gt;).&lt;br /&gt;Reste la lecture du résultat, qui n&#39;est de loin pas la partie la plus triviale.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;Ne pas bufferiser la lecture du résultat&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;L&#39;implémentation d&#39;un serveur proxy dans laquelle on lit le résultat en entier (via un lib du style httpclient) avant de l&#39;envoier ensuite au navigateur n&#39;est à mon avis pas bonne : le délai entre la requête et la réponse risque d&#39;en prendre un coup, surtout pour les grosses pages.&lt;br /&gt;L&#39;idée est donc de retourner directement les bytes lus du serveur web au client.&lt;br /&gt;&lt;br /&gt;En pseudo code, ca donne quelque chose du style :&lt;br /&gt;&lt;pre&gt; // fromWeb : InputStream du socket de la connexion vers le serveur source&lt;br /&gt;// toBrowser : OutputStream du socket de la connexion vers le browser&lt;br /&gt;while ((i = fromWeb.read(buffer)) != -1) {&lt;br /&gt;  toBrowser.write(buffer, 0, i);&lt;br /&gt;  toBrowser.flush();&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;Fermeture des connexions&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;La fermeture des connexions est très importante afin de libérer les ressources et ne pas avoir un serveur qui explose après 20 requêtes. Facile en théorie, la fermeture de la connexion est la sous partie non triviale. Dans la mesure où le serveur ne ferme pas systématiquement la connexion à la fin du transfert si il reçoit un header &quot;&lt;span style=&quot;font-style: italic;&quot;&gt;Connection: keep-alive&lt;/span&gt;&quot;, il faut détecter quand la réponse du serveur est complète pour pouvoir fermer la connexion.&lt;br /&gt;&lt;br /&gt;Dans une grande majorité des réponses, la taille de la réponse est spécifiée via un header &quot;Content-Length: 82&quot;. Il suffit donc de lire autant de bytes que nécessaire et la connexion peut être fermée. Mais quelques réponses ne vont pas retourner de taille. C&#39;est le cas par exemple lors du streaming d&#39;un fichier. Dans ce cas il faut lire la réponse jusqu&#39;à ce que le serveur ferme lui-même la connexion.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;Transfer-Encoding: chunked&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Une autre difficulté à la lecture de la réponse est l&#39;encodage &lt;span style=&quot;font-style: italic;&quot;&gt;chunked&lt;/span&gt;. Dans ce mode de transfert, le serveur sépare la réponse en plusieurs parties, les &lt;span style=&quot;font-style: italic;&quot;&gt;chunks&lt;/span&gt;. Ca lui permet d&#39;envoyer une partie de la réponse tout en calculant la suite. Par exemple Google utilise ce mode de réponse : les 2-3 premiers résultats sont dans un cache direct, et Google les retourne dans un premier chunk. Puis il doit aller chercher les 7-8 autres dans un deuxième cache, opération un peu plus coûteuse, qui se fait pendant que le navigateur du client lit ce premier &lt;span style=&quot;font-style: italic;&quot;&gt;chunk&lt;/span&gt;. Ca permet au serveur de ne pas attendre d&#39;avoir entièrement cherché les 10 résultats, et de profiter du temps de transfert avec le client. Du point de vu du client, une fois qu&#39;il a fini de lire le premier chunk, les suivants sont prêts à être lus. L&#39;impression de fluidité est donc parfaite. Mais malheureusement peu d&#39;implémentations tirent intelligemment profit de ce type de transfert.&lt;br /&gt;&lt;br /&gt;En pratique, la réponse d&#39;une encodage &lt;span style=&quot;font-style: italic;&quot;&gt;chunked&lt;/span&gt; donne quelque chose du style :&lt;br /&gt;&lt;blockquote&gt;taille du chunk en hexa \r\n&lt;br /&gt;données \r\n&lt;br /&gt;taille du prochain chunk \r\n&lt;br /&gt;données \r\n&lt;br /&gt;...&lt;br /&gt;0\r\n&lt;br /&gt;\r\n&lt;/blockquote&gt;Pour lire la réponse, il faut donc lire la taille du &lt;span style=&quot;font-style: italic;&quot;&gt;chunk&lt;/span&gt;, lire les données du &lt;span style=&quot;font-style: italic;&quot;&gt;chunk&lt;/span&gt;, lire la taille du prochain &lt;span style=&quot;font-style: italic;&quot;&gt;chunk&lt;/span&gt;, etc jusqu&#39;à ce qu&#39;on ait un &lt;span style=&quot;font-style: italic;&quot;&gt;chunk&lt;/span&gt; de taille null, signifiant la fin de la réponse.&lt;br /&gt;&lt;pre&gt;HTTP/1.1 200 OK¶&lt;br /&gt;Date: Fri, 31 Dec 1999 23:59:59 GMT¶&lt;br /&gt;Content-Type: text/plain¶&lt;br /&gt;Transfer-Encoding: chunked¶&lt;br /&gt;¶&lt;br /&gt;1a¶&lt;br /&gt;abcdefghijklmnopqrstuvwxyz¶&lt;br /&gt;10¶&lt;br /&gt;1234567890abcdef¶&lt;br /&gt;0¶&lt;br /&gt;¶&lt;/pre&gt;&lt;span style=&quot;font-size:130%;&quot;&gt;Caching&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Prochaine étape dans l&#39;implémentation d&#39;un serveur de cache utile est efficace, c&#39;est l&#39;ajout d&#39;une couche de cache au niveau du proxy : le serveur cible va retourner une information sur la date de dernière modification de la page. Cette indication peut être utilisé pour retourner la page mise en cache plutôt que de relire la réponse du serveur.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size:130%;&quot;&gt;Authentification &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Dernier point important si on met un serveur proxy sur internet, il faut ABSOLUMENT implémenter un ACL (access control list) afin de restreindre l&#39;accès et l&#39;utilisation du proxy aux personnes authentifiées uniquement. Faute de quoi votre tout beau serveur proxy sera vitre trouvé et utilisé par des personnes malveillantes pour spammer, consulter des sites illégaux etc.&lt;br /&gt;&lt;br /&gt;Prochaine étape : au travail !</content><link rel='replies' type='application/atom+xml' href='http://benoitperroud.blogspot.com/feeds/2925541384205042937/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/5001452664427688683/2925541384205042937' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5001452664427688683/posts/default/2925541384205042937'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5001452664427688683/posts/default/2925541384205042937'/><link rel='alternate' type='text/html' href='http://benoitperroud.blogspot.com/2008/06/implmentation-dun-serveur-proxy-http.html' title='Implémentation d&#39;un serveur proxy HTTP'/><author><name>KillerWhile</name><uri>http://www.blogger.com/profile/17113505481300913194</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://www.noisette.ch/wiki/images/Raquette18.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5001452664427688683.post-457285031185346163</id><published>2008-06-05T06:21:00.004+02:00</published><updated>2008-06-08T20:17:25.490+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="security"/><category scheme="http://www.blogger.com/atom/ns#" term="smtp"/><title type='text'>Mettre à mal un réseau d&#39;entreprise avec Outlook (TM, R &amp; CO)</title><content type='html'>Suite à une expérience involontaire d&#39;un collègue de travail, on a eu 30 ordinateurs bloqués une quinzaine de minute :&lt;br /&gt;&lt;br /&gt;Notre serveur SVN envoie un mail à chaque commit à une mailinglist interne, à laquelle une trentaine de collaborateurs est abonné. Le commit incriminé était certes quelque peu conséquent, une colonne ajoutée dans un fichier CSV de 5000 lignes, mais la conséquence était désastreuse !&lt;br /&gt;&lt;br /&gt;Le mail faisait ~ 5Mb, et le diff du commit était formaté en HTML. Tous les collaborateurs qui ont cliqué sur le mail avec le preview activé n&#39;ont pas eu d&#39;autre choix que de tuer Outlook après avoir eu l&#39;ordinateur bloqué un bon moment.&lt;br /&gt;&lt;br /&gt;Moi qui n&#39;était déjà pas un grand amoureux d&#39;Outlook et de son immense capacité à accomplir des recherches performante parmi les mails, me voici comblé.&lt;br /&gt;&lt;br /&gt;Mais pourquoi donc autant d&#39;entreprise s&#39;accrochent-ils à ce logiciel ? Dans tous les cas, si vous voulez forcer un peu la main pour le passage à un autre logiciel, vous savez ce qu&#39;il reste à faire.</content><link rel='replies' type='application/atom+xml' href='http://benoitperroud.blogspot.com/feeds/457285031185346163/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/5001452664427688683/457285031185346163' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5001452664427688683/posts/default/457285031185346163'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5001452664427688683/posts/default/457285031185346163'/><link rel='alternate' type='text/html' href='http://benoitperroud.blogspot.com/2008/06/mettre-mal-un-rseau-dentreprise-avec.html' title='Mettre à mal un réseau d&#39;entreprise avec Outlook (TM, R &amp; CO)'/><author><name>KillerWhile</name><uri>http://www.blogger.com/profile/17113505481300913194</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://www.noisette.ch/wiki/images/Raquette18.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5001452664427688683.post-8357443813819199630</id><published>2008-02-23T13:42:00.000+01:00</published><updated>2008-02-23T12:42:55.200+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="apache"/><category scheme="http://www.blogger.com/atom/ns#" term="browser"/><category scheme="http://www.blogger.com/atom/ns#" term="seo"/><title type='text'>Une liste de USER AGENTS parsable</title><content type='html'>Il est toujours utile d&#39;avoir sous la main une liste de USER AGENTS facilement &lt;span style=&quot;font-style: italic;&quot;&gt;parsable&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;La mienne, qui ne contient que des USER AGENTS ^Mozilla/.* se trouve à l&#39;adresse &lt;a href=&quot;http://www.noisette.ch/useragents/&quot;&gt;http://www.noisette.ch/useragents/&lt;/a&gt;. Elle est mises-à-jour journalièrement sur la base des navigateurs qui se connectent sur mon serveur, tous sites confondus. Elle va donc suivre l&#39;évolution des numéros de version des Firefox et autres IE...&lt;br /&gt;&lt;br /&gt;Cette liste, couplée à la fonction &lt;a href=&quot;http://benoitperroud.blogspot.com/2007/11/fonction-urlgetcontents-en-php.html&quot;&gt;url_get_contents &lt;/a&gt; définie antérieurement, permet facilement de disposer d&#39;un USER AGENT pour faire ce qu&#39;il est possible de faire avec un USER AGENT généré :)&lt;br /&gt;&lt;br /&gt;Illustration en PHP :&lt;br /&gt;&lt;pre&gt;$useragents = explode(&quot;\n&quot;, url_get_contents(&#39;http://www.noisette.ch/useragents/list.txt&#39;));&lt;br /&gt;$useragent = $useragents[rand(0, count($useragents) - 1)];&lt;br /&gt;&lt;/pre&gt;</content><link rel='replies' type='application/atom+xml' href='http://benoitperroud.blogspot.com/feeds/8357443813819199630/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/5001452664427688683/8357443813819199630' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5001452664427688683/posts/default/8357443813819199630'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5001452664427688683/posts/default/8357443813819199630'/><link rel='alternate' type='text/html' href='http://benoitperroud.blogspot.com/2008/02/list-de-user-agents-exploitable.html' title='Une liste de USER AGENTS parsable'/><author><name>KillerWhile</name><uri>http://www.blogger.com/profile/17113505481300913194</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://www.noisette.ch/wiki/images/Raquette18.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5001452664427688683.post-1524269656106851496</id><published>2008-02-18T12:53:00.000+01:00</published><updated>2008-02-18T11:55:19.545+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="algorithm"/><category scheme="http://www.blogger.com/atom/ns#" term="optimisation"/><category scheme="http://www.blogger.com/atom/ns#" term="sql"/><title type='text'>De la concurrence des requêtes SQL</title><content type='html'>Sans cité &lt;a href=&quot;http://fr.wikipedia.org/wiki/Michel_de_Montaigne&quot;&gt;Montaigne&lt;/a&gt;, voici un cas académique dans lequel la concurrence des requêtes SQL est souvent oubliée.&lt;br /&gt;&lt;br /&gt;Nous avons une table &lt;span style=&quot;font-style: italic;&quot;&gt;hits&lt;/span&gt; qui contient 4 champs : une date (nommé &lt;span style=&quot;font-style: italic;&quot;&gt;date&lt;/span&gt;), une clé étrangère pointant vers un objet du système (nommée &lt;span style=&quot;font-style: italic;&quot;&gt;object_id&lt;/span&gt;) et un compteur implémenté sous ca forme la plus simple : un entier (nommé &lt;span style=&quot;font-style: italic;&quot;&gt;counter&lt;/span&gt;). Puisqu&#39;on travail avec une framework qui implémente de l&#39;&lt;a href=&quot;http://en.wikipedia.org/wiki/Active_record_pattern&quot;&gt;&lt;span style=&quot;font-style: italic;&quot;&gt;active record&lt;/span&gt;&lt;/a&gt; on ajoute un champ &lt;span style=&quot;font-style: italic;&quot;&gt;id&lt;/span&gt; qui fera office de clé primaire.&lt;br /&gt;A chaque utilisation de l&#39;objet référencé par la clé étrangère on souhaite incrémenter le compteur et recommencer à 0 tous les minuits afin d&#39;avoir un historique journalier de l&#39;utilisation de l&#39;objet. Alors comme on a quand même un peu réfléchi à la performance du système (un billet sur le sujet est en préparation), on définit un index composé des champs &lt;span style=&quot;font-style: italic;&quot;&gt;date&lt;/span&gt; et &lt;span style=&quot;font-style: italic;&quot;&gt;object_id&lt;/span&gt;. Puis on définit la fonction suivante, donnée ci-dessous en pseudo-code, qui incrémente notre compteur et insère un nouveau tuple si aucun n&#39;existe pour le jour courant :&lt;br /&gt;&lt;pre&gt;void function hit ( int $object_id ) {&lt;br /&gt;  SELECT FROM hits WHERE object_id = $object_id AND date = NOW()&lt;br /&gt;  if (row_exists)&lt;br /&gt;      UPDATE hits SET counter = counter + 1 WHERE  object_id = $object_id AND date = NOW()&lt;br /&gt;  else&lt;br /&gt;      INSERT INTO hits (object_id, date, counter) VALUES ($object_id, NOW(), 1)&lt;br /&gt;}&lt;/pre&gt;Tout se passe bien jusqu&#39;au jour où on se rend compte qu&#39;il y a plusieurs lignes par objet et par jour dans la base de données.&lt;br /&gt;&lt;br /&gt;Ce problème vient du fait qu&#39;il peut se passer un temps indéterminé entre la requête &lt;span style=&quot;font-style: italic;&quot;&gt;SELECT&lt;/span&gt; et l&#39;&lt;span style=&quot;font-style: italic;&quot;&gt;INSERT&lt;/span&gt;. Si à 00h01 2 requêtes sont faites en même temps sur le même objet, il est fort probable que 2 requêtes &lt;span style=&quot;font-style: italic;&quot;&gt;SELECT&lt;/span&gt; soient faites avant un &lt;span style=&quot;font-style: italic;&quot;&gt;INSERT&lt;/span&gt;, et donc les 2 tests&lt;span style=&quot;font-family:monospace;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-style: italic;&quot;&gt;if (row_exists)&lt;/span&gt; vont retourner faux et 2 &lt;span style=&quot;font-style: italic;&quot;&gt;INSERT&lt;/span&gt; seront fait.&lt;br /&gt;&lt;br /&gt;Les solutions pour résoudre ce problème sont multiples, elles passent de la redéfinition de la clé primaire en &lt;span style=&quot;font-style: italic;&quot;&gt;date&lt;/span&gt;, &lt;span style=&quot;font-style: italic;&quot;&gt;object_id&lt;/span&gt; plutôt que notre champ &lt;span style=&quot;font-style: italic;&quot;&gt;id&lt;/span&gt;, ce qui aurait comme comportement de faire échouer le 2ème &lt;span style=&quot;font-style: italic;&quot;&gt;INSERT&lt;/span&gt;, erreur qui pourrait être capturée et traitée spécifiquement. Une autre solution serait de mettre un verrou sur la fonction, chose très aisée en Java avec le mot-clé &lt;span style=&quot;font-style: italic;&quot;&gt;synchronized&lt;/span&gt;. La fonction deviendrait &lt;span style=&quot;font-style: italic;&quot;&gt;void synchronized function hit(int object_id)&lt;/span&gt;, évitant ainsi ce type de problème de concurrence.&lt;br /&gt;&lt;br /&gt;Dans tous les cas les applications web sont aussi (voir même plus) soumises aux problèmes de concurrence, et l&#39;expérience nous montre que la technique de l&#39;autruche de même que les phrases du style &quot;Il ne PEUT PAS y avoir 2 requêtes en même temps&quot; sont à bannir absolument.</content><link rel='replies' type='application/atom+xml' href='http://benoitperroud.blogspot.com/feeds/1524269656106851496/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/5001452664427688683/1524269656106851496' title='4 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5001452664427688683/posts/default/1524269656106851496'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5001452664427688683/posts/default/1524269656106851496'/><link rel='alternate' type='text/html' href='http://benoitperroud.blogspot.com/2008/02/de-la-concurrence-des-requtes-sql.html' title='De la concurrence des requêtes SQL'/><author><name>KillerWhile</name><uri>http://www.blogger.com/profile/17113505481300913194</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://www.noisette.ch/wiki/images/Raquette18.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5001452664427688683.post-6263699928333617862</id><published>2008-01-29T11:16:00.000+01:00</published><updated>2008-01-29T11:34:45.044+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="privacy"/><category scheme="http://www.blogger.com/atom/ns#" term="security"/><category scheme="http://www.blogger.com/atom/ns#" term="thinking"/><category scheme="http://www.blogger.com/atom/ns#" term="web 2.0"/><title type='text'>Vos données sont-elles réellement privées ?</title><content type='html'>&lt;span style=&quot;font-size:130%;&quot;&gt;Donnez des informations pour exister&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Le principe premier du Web 2.0 est la participation des utilisateurs. Pour les sites sociaux comme MySpace et Facebook, où la participation se calcule en quantité d&#39;informations données sur soi-même.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size:130%;&quot;&gt;Collecte indirecte d&#39;informations&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;L&#39;aspect de collaboration entre les membres résulte en une masse d&#39;information indirecte enregistrée souvent au dépend de la personne ciblée :&lt;br /&gt;&lt;br /&gt;Facebook par exemple enregistre des informations sur vous par rapport aux détails que donnent vos amis (appelé Social map) : à chaque ajout de nouvel &lt;span style=&quot;font-style: italic;&quot;&gt;ami&lt;/span&gt;, vous avez la possibilité de spécifier comment vous l&#39;avez connu. Grâce à ce système subtile, mon profile Facebook sait maintenant que j&#39;ai fini l&#39;EPFL en 2007, que je fais partie d&#39;autres associations, ... alors que je n&#39;ai rien renseigner sur ces sujets précis.&lt;br /&gt;&lt;span style=&quot;font-size:130%;&quot;&gt;&lt;br /&gt;Le business des données personnelles&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Le fait d&#39;être encouragé à compléter son profil qui n&#39;est complet qu&#39;a 88% comme nous l&#39;indique de manière bien visible Linkedin n&#39;est pas entièrement désintéressé : le fait de connaitre précisément ses utilisateurs et d&#39;en dresser des profils augmentent largement les marges sur les revenus publicitaires qui seront mieux ciblés donc plus percutant donc plus &lt;span style=&quot;font-style: italic;&quot;&gt;intéressant&lt;/span&gt; pour l&#39;utilisateur. Revenus publicitaires qui sont, rappelons-le, le &lt;span style=&quot;font-style: italic;&quot;&gt;business model&lt;/span&gt; principal des ces sites sociaux.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size:130%;&quot;&gt;Protection des données&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;L&#39;aspect à ne pas perdre de vu si on utilise ce genre de sites, c&#39;est que ça n&#39;est pas une simple cas à cocher &quot;Rendre mon profil privé&quot; qui protègera réellement les données de votre profile : les données sont chez une personne tierce qui d&#39;un jour à l&#39;autre peut décider d&#39;en faire autre chose. Ou, comme c&#39;est le cas sur MySpace, une vulnérabilité du site permet d&#39;outerpasser cette coche ridicule...&lt;br /&gt;&lt;br /&gt;La réponse au titre du billet est clairement NON ! Le fait de déposer vos données sur un service externe quelconque ne les rendent pas privées. Donc soit vous ne mettez que des informations &lt;span style=&quot;font-weight: bold;&quot;&gt;réellement publiques&lt;/span&gt; sur votre profil, soit vous faites confiance à 100% au service et vous ne vous demanderez pas d&#39;où viennent les données sur vous retrouvées dans la nature...&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size:130%;&quot;&gt;Ils en parlent&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Faille de sécurité qui perment de voir les photos privée d&#39;un profil sur Myspace : &lt;a href=&quot;http://www.wired.com/politics/security/news/2008/01/myspace_torrent&quot;&gt;http://www.wired.com/politics/security/news/2008/01/myspace_torrent&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Nos données personnelles sur Facebook : &lt;a href=&quot;http://standblog.org/blog/post/2008/01/10/De-lavenir-de-Facebook-et-de-nos-donnees-personnelles&quot;&gt;http://standblog.org/blog/post/2008/01/10/De-lavenir-de-Facebook-et-de-nos-donnees-personnelles&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Système de publicité intrusive sur Facebook : &lt;a href=&quot;http://www.infos-du-net.com/actualite/12304-facebook-publicite-internautes.html&quot;&gt;http://www.infos-du-net.com/actualite/12304-facebook-publicite-internautes.html&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;</content><link rel='replies' type='application/atom+xml' href='http://benoitperroud.blogspot.com/feeds/6263699928333617862/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/5001452664427688683/6263699928333617862' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5001452664427688683/posts/default/6263699928333617862'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5001452664427688683/posts/default/6263699928333617862'/><link rel='alternate' type='text/html' href='http://benoitperroud.blogspot.com/2008/01/vos-donnes-sont-elles-rellement-prives.html' title='Vos données sont-elles réellement privées ?'/><author><name>KillerWhile</name><uri>http://www.blogger.com/profile/17113505481300913194</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://www.noisette.ch/wiki/images/Raquette18.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5001452664427688683.post-2231561896167883878</id><published>2007-12-30T22:39:00.000+01:00</published><updated>2007-12-30T23:46:20.784+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="thinking"/><title type='text'>Je télécharge mes MP3 et les écoute légalement.</title><content type='html'>Le parlement et le conseil national ont accepté le 5 Octobre 2007 presque sans aucune résistance une &lt;a href=&quot;http://www.ige.ch/F/jurinfo/j103.shtm&quot;&gt;loi fédérale sur le droit d&#39;auteur et les droits voisins&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Pour toute question à propos du référendum lancé, que dit en passant j&#39;encourage fortement à signer, rendez-vous sur le site &lt;a href=&quot;http://www.no-dmca.ch/&quot;&gt;No Swiss DMCA&lt;/a&gt;.&lt;br /&gt;Je n&#39;essayerai pas non plus de déterminer à quelles mesures techniques, notées &lt;span style=&quot;font-style: italic;&quot;&gt;efficaces&lt;/span&gt;, le texte de loi fait peut bien faire référence.&lt;br /&gt;&lt;br /&gt;Cette loi, plus précisément l&#39;article 39a alinéa 4 donné ci-après, combiné à l&#39;approbation du Tribunal fédéral (TF) sur l&#39;introduction d&#39;une redevance sur les supports numériques (baladeurs MP3, iPod et autres enregistreurs à disques durs) entrée en vigueur au 1er septembre 2007, me mène à la conclusion suivante :&lt;br /&gt;&lt;br /&gt;Je vais télécharger de la musique sur mon réseau peer-to-peer préféré, &lt;a href=&quot;http://fr.wikipedia.org/wiki/Ripper&quot;&gt;ripper&lt;/a&gt; des CDs et retirer les DMA de mes MP3 restants (autrement dit : contourner les mesures techniques &lt;span style=&quot;font-style: italic;&quot;&gt;efficaces&lt;/span&gt;) et l&#39;écouter (exclusivement) sur mon baladeur MP3 récemment acquis. Celui-ci étant taxé, je m&#39;affranchis de toute autre taxe, et je deviens entièrement légal. Idem pour les divx !&lt;br /&gt;&lt;blockquote&gt;Art 39a&lt;br /&gt;4 L’interdiction de contourner ne peut pas frapper celui qui contourne une mesure technique efficace exclusivement dans le but de procéder à une utilisation licite.&lt;/blockquote&gt;PS : cet article n&#39;est pas illégale au sens de l&#39;Art 39a 3a, c&#39;est-à-dire que cet article ne fait pas promotion visant à contourner des mesures techniques efficaces.&lt;br /&gt;PPS : la critique de la double imposition à une taxe sur les droits d&#39;auteurs des musiques achetées sur un online music shop et écoutées sur un baladeur taxé fera l&#39;objet d&#39;un autre article.</content><link rel='replies' type='application/atom+xml' href='http://benoitperroud.blogspot.com/feeds/2231561896167883878/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/5001452664427688683/2231561896167883878' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5001452664427688683/posts/default/2231561896167883878'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5001452664427688683/posts/default/2231561896167883878'/><link rel='alternate' type='text/html' href='http://benoitperroud.blogspot.com/2007/12/je-tlcharge-mes-mp3-et-les-coute.html' title='Je télécharge mes MP3 et les écoute légalement.'/><author><name>KillerWhile</name><uri>http://www.blogger.com/profile/17113505481300913194</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://www.noisette.ch/wiki/images/Raquette18.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5001452664427688683.post-2726925922373297212</id><published>2007-12-30T22:31:00.000+01:00</published><updated>2007-12-30T22:37:43.442+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="seo"/><category scheme="http://www.blogger.com/atom/ns#" term="wireless"/><title type='text'>Offrir un réseau wifi ouvert pour rentabiliser sa connexion Internet</title><content type='html'>J&#39;écrivais il y a un bon moment comment un administrateur réseau peu scrupuleux pouvait &lt;a href=&quot;http://benoitperroud.blogspot.com/2006/09/gagner-de-largent-grce-aux-botnets.html&quot;&gt;arrondir ses fins de mois en détournant les publicités des sites&lt;/a&gt; visités par les utilisateurs&lt;br /&gt;interne.&lt;br /&gt;&lt;br /&gt;Cette technique s&#39;adapte très simplement à un réseau wifi ouvert...&lt;br /&gt;&lt;br /&gt;Mais attention au &lt;a href=&quot;http://en.wikipedia.org/wiki/Click-through_rate&quot;&gt;click through rate&lt;/a&gt; trop élevé :)</content><link rel='replies' type='application/atom+xml' href='http://benoitperroud.blogspot.com/feeds/2726925922373297212/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/5001452664427688683/2726925922373297212' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5001452664427688683/posts/default/2726925922373297212'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5001452664427688683/posts/default/2726925922373297212'/><link rel='alternate' type='text/html' href='http://benoitperroud.blogspot.com/2007/12/offrir-un-rseau-wifi-ouvert-pour.html' title='Offrir un réseau wifi ouvert pour rentabiliser sa connexion Internet'/><author><name>KillerWhile</name><uri>http://www.blogger.com/profile/17113505481300913194</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://www.noisette.ch/wiki/images/Raquette18.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5001452664427688683.post-3347246719893979057</id><published>2007-12-15T16:14:00.000+01:00</published><updated>2007-12-15T15:14:52.927+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="bullshit"/><category scheme="http://www.blogger.com/atom/ns#" term="web 2.0"/><title type='text'>Twitter, un vrai service Web 2.0 (le retour)</title><content type='html'>Pour commencer j&#39;ose espérer que le 2ème degré du &lt;a href=&quot;http://benoitperroud.blogspot.com/2007/12/twitter-un-vrai-service-web-20.html&quot;&gt;message précédent&lt;/a&gt; a été perçu.&lt;br /&gt;&lt;br /&gt;&lt;a href=&quot;http://www.twitter.com&quot;&gt;Twitter&lt;/a&gt; est selon moi un vrai service Web 2.0, c&#39;est-à-dire qu&#39;il ne sert à rien. On n&#39;est pas plus heureux en l&#39;ayant découvert et ça ne fait pas avancer la société de l&#39;utiliser.&lt;br /&gt;&lt;br /&gt;Mais au-delà de considération subjectives à son sujet, les technologies et les techniques d&#39;addiction mises en oeuvre sur ce site sont suffisamment intéressantes pour être discutées ici :&lt;br /&gt;&lt;br /&gt;Premièrement les méthodes de publication disponibles sont autant multiples que variées :&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Interface web,&lt;br /&gt;&lt;/li&gt;&lt;li&gt;SMS,&lt;br /&gt;&lt;/li&gt;&lt;li&gt;IM (client jabber),&lt;/li&gt;&lt;li&gt;...&lt;/li&gt;&lt;/ul&gt;On voit d&#39;entrée que le service est fait pour être mis-à-jour en permanence, très facilement par IM quand on est devant un ordinateur relié à Internet, mais aussi via des dispositifs mobiles une fois le clavier de l&#39;ordinateur hors de porté. Ainsi un utilisateur peut à tout moment renseigner ses lecteurs virtuels et potentiels sur ce qu&#39;il est en train de faire. L&#39;aspect mise-à-jour via téléphone portable est très important, car il permet de modifier le statut lors des sorties, donc quand c&#39;est le plus croustillant.&lt;br /&gt;&lt;br /&gt;Un aspect important pour renforcer l&#39;addiction est la possibilité d&#39;émettre un rappel (SMS ou email) en cas de non mise-à-jour prolongée.&lt;br /&gt;&lt;br /&gt;Deuxièmement les différents formats de lecture possibles sont aussi standard que tendance : on retrouve ainsi la &quot;&lt;span style=&quot;font-style: italic;&quot;&gt;social timeline&lt;/span&gt;&quot; sur sa page personnelle au style très épuré Web 2.0 et le fameux flux RSS. La communauté de lecteurs n&#39;est pas en reste non plus, avec son lot de features pour se créer un réseau d&#39;&lt;span style=&quot;font-style: italic;&quot;&gt;amis&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Pour conclure sur cet article plutôt bullshit&#39;stisant pour reprendre les termes d&#39;autres, je dirais que mis à part le côté &quot;sert-à-rien&quot; il pourrait remplacer à merveille les blogs que les jeunes s&#39;efforcent d&#39;utiliser de la manière dont Twitter oblige, la possibilité de mettre les photos en mois. Et que le côté publication d&#39;activité via IM est réellement bien fait.</content><link rel='replies' type='application/atom+xml' href='http://benoitperroud.blogspot.com/feeds/3347246719893979057/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/5001452664427688683/3347246719893979057' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5001452664427688683/posts/default/3347246719893979057'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5001452664427688683/posts/default/3347246719893979057'/><link rel='alternate' type='text/html' href='http://benoitperroud.blogspot.com/2007/12/twitter-un-vrai-service-web-20-le.html' title='Twitter, un vrai service Web 2.0 (le retour)'/><author><name>KillerWhile</name><uri>http://www.blogger.com/profile/17113505481300913194</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://www.noisette.ch/wiki/images/Raquette18.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5001452664427688683.post-5892447238518830616</id><published>2007-12-15T13:24:00.000+01:00</published><updated>2007-12-15T12:24:53.143+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="fun"/><category scheme="http://www.blogger.com/atom/ns#" term="web 2.0"/><title type='text'>Twitter, un vrai service Web 2.0</title><content type='html'>D&#39;abord il y a eu les &lt;a href=&quot;http://fr.wikipedia.org/wiki/Blog&quot;&gt;blogs&lt;/a&gt;, qui permettaient de raconter sa vie&lt;br /&gt; passionnante de tous les jours, puis maintenant il y a &lt;a href=&quot;http://twitter.com&quot;&gt;Twitter&lt;/a&gt;, qui force de&lt;br /&gt;résumer sa vie passionnante en 140 caractères.&lt;br /&gt;&lt;br /&gt;Comme je n&#39;ai pas une vie passionnante, 140 caractères sont longtemps suffisant pour expliquer que je vais au travail, je suis bloqué sur un problème en PHP, j&#39;ai vu un site super, j&#39;ai mangé au Delectis à midi et que &quot;Tien, c&#39;est déjà 16h30 alors je vais rentrer&quot;.&lt;br /&gt;&lt;br /&gt;Donc je vous invite tous à retrouver le fil RSS de ma vie &lt;a href=&quot;http://twitter.com/killerwhile&quot;&gt;La vie au format RSS de Benoit Perroud&lt;/a&gt;.</content><link rel='replies' type='application/atom+xml' href='http://benoitperroud.blogspot.com/feeds/5892447238518830616/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/5001452664427688683/5892447238518830616' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5001452664427688683/posts/default/5892447238518830616'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5001452664427688683/posts/default/5892447238518830616'/><link rel='alternate' type='text/html' href='http://benoitperroud.blogspot.com/2007/12/twitter-un-vrai-service-web-20.html' title='Twitter, un vrai service Web 2.0'/><author><name>KillerWhile</name><uri>http://www.blogger.com/profile/17113505481300913194</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='29' height='32' src='http://www.noisette.ch/wiki/images/Raquette18.jpg'/></author><thr:total>0</thr:total></entry></feed>